Connor
Connor

Reputation: 244

Search multiple indexes and return correct types

I have two indexes set up in Elasticsearch storing different types of data and I'm attempting to get search results using nest from both indexes at the same time. I have set up models like the following...

public class Person
{
    [Number(Name="person_id")]
    public int Id { get; set; }
    [Date(Name = "person_created")]
    public DateTime Created { get; set; }
    ...
}

public class Work {
    [Number(Name="work_id")]
    public int Id { get; set; }
    [Date(Name = "work_created")]
    public DateTime Created { get; set; }
    ...
}

When querying on a single index I'm able to do the following and get my results back mapped to my model type...

var request = new SearchRequest("works")
{
    From = searchQuery.Offset,
    Size = searchQuery.PageSize,
    Query = new QueryStringQuery { Query = searchQuery.SearchTerm },
 };

 var result = _elasticClient.Search<Work>(request);

However when doing a query like the following how do I tell nest what types to map results to per index?

var request = new SearchRequest("works,person")
{
     ...
}
var result = _elasticClient.Search<object> ...

Other answers I've seen suggest doing something like the following but I think the Types function has been removed in NEST 7.0...

client.Search<object>(s => s
    .Size(100)
    .SearchType(SearchType.Count)
    .Type(Types.Type(typeof(Dog), typeof(Cat)))

Upvotes: 1

Views: 1236

Answers (1)

Rob
Rob

Reputation: 9979

If you are in control of document indexing you could take advantage of the possibility to customize JSON serialization process in NEST, by placing .NET type within a document in an elasticsearch index. This way NEST will deserialize documents into correct types.

class Program
{
    public class Person  
    {
        [Number(Name="person_id")]
        public int Id { get; set; }
        [Date(Name = "person_created")]
        public DateTime Created { get; set; }
    }

    public class Work 
    {
        [Number(Name="work_id")]
        public int Id { get; set; }
        [Date(Name = "work_created")]
        public DateTime Created { get; set; }
    }

    static void Main(string[] args)
    {
        var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
        var connectionSettings =
            new ConnectionSettings(pool,
                sourceSerializer: (builtin, settings) => new JsonNetSerializer(builtin, settings,
                    () => new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.All}
                ));
        var client = new ElasticClient(connectionSettings);

        var deleteIndexResponse = client.Indices.Delete("person,work");

        var createIndexResponse = client.Indices
            .Create("person", i => i.Map<Person>(m => m.AutoMap()));
        var createIndexResponse2 = client.Indices
            .Create("work", i => i.Map<Work>(m => m.AutoMap()));

        client.Index(new Person {Id = 1, Created = DateTime.UtcNow},
            i => i.Index("person"));
        client.Index(new Work {Id = 1, Created = DateTime.UtcNow},
            i => i.Index("work"));

        client.Indices.Refresh();

        var searchResponse = client.Search<object>(s => s
            .Index("person,work")
            .Query(q => q.MatchAll()));

        foreach (var document in searchResponse.Documents)
        {
            Console.WriteLine($"Person? {document is Person} Work? {document is Work}");
        }
    }
}

Prints:

Person? True Work? False
Person? False Work? True

NEST.JsonNetSerializer package needs to be installed in your project.

Hope that helps.

Upvotes: 1

Related Questions