Using NEST for elasticsearch. How can I search for parents based on children attributes

0

I am trying to do a simple search, using NEST for customers given specific customer locations. The POCOS are:

class Customer
{
    public int CustomerId { get; set; }
    public string CustomerName { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Identifiers { get; set; }
    public string isIndividual { get; set; }
    public double Balance { get; set; }
    public List<CustomerLocation> Locations { get; set; }

class CustomerLocation
{
    public int CustomerLocationId { get; set; }
    public string StreetLine1 { get; set; }
    public string Streetline2 { get; set; }
    public string City { get; set; }
   
}

Currently I am using this search routine - but it fails:

                        var searchResponse = _client.Search<Customer>(s => s
                   .Query(q => q
                        .HasChild<CustomerLocation >(hp => hp
                            .Query(qq => qq
                                .Match(m => m
                                    .Field(f => f.City )
                                    .Query(queryText)
                                )
                                
                            )
                         )
                     )
                   .Size(500)
                    );

The error message provided is:

System.Exception HResult=0x80131500 Message=Invalid search. Error is: Invalid NEST response built from a unsuccessful (400) low level call on POST: /customers/_search?typed_keys=true

Audit trail of this API call:

  • [1] SniffOnStartup: Took: 00:00:00.2448689
  • [2] SniffSuccess: Node: http://localhost:9200/ Took: 00:00:00.2288784
  • [3] PingSuccess: Node: http://127.0.0.1:9200/ Took: 00:00:00.0029899
  • [4] BadResponse: Node: http://127.0.0.1:9200/ Took: 00:00:00.1639172

OriginalException: Elasticsearch.Net.ElasticsearchClientException: The remote server returned an error: (400) Bad Request.. Call: Status code 400 from: POST /customers/_search?typed_keys=true. ServerError: Type: search_phase_execution_exception Reason: "all shards failed" ---> System.Net.WebException: The remote server returned an error: (400) Bad Request.

at System.Net.HttpWebRequest.GetResponse() at Elasticsearch.Net.HttpWebRequestConnection.Request[TResponse](RequestData requestData) in C:\Users\russc\source\elasticsearch-net\src\Elasticsearch.Net\Connection\HttpWebRequestConnection.cs:line 63

Any ideas - much appreciated.

c#
elasticsearch
nest
asked on Stack Overflow Aug 20, 2020 by WaterBoy

1 Answer

0

The relationship between customers and locations is not a parent/child relationship in Elasticsearch terms, which is required in order to use the has_child query.

Unless explicitly mapped, the Locations property on Customer will be an object type mapping, which would allow you to do

var queryText = "Sydney";

var searchResponse = client.Search<Customer>(s => s
    .Query(q => q
       .Match(m => m
           .Field(f => f.Locations.First().City)
           .Query(queryText)
       )
    )
    .Size(500)
);

Note: f => f.Locations.First().City is simply an expression to build a path to the JSON field in a strongly typed fashion, by navigating the object graph. It does not mean "the first location's city", but evaluates to "any location's city".

This generates the following query

{
  "query": {
    "match": {
      "locations.city": {
        "query": "Sydney"
      }
    }
  },
  "size": 500
}

With the given POCO structure however, it's likely that you'll want to search across multiple location properties. In that case, Locations should be explicitly mapped as a nested data type.

When mapped as a nested data type, the query would be

var queryText = "Sydney";

var searchResponse = client.Search<Customer>(s => s
    .Query(q => q
        .Nested(n => n
            .Path(p => p.Locations)
            .Query(nq => nq
                .Match(m => m
                    .Field(f => f.Locations.First().City)
                    .Query(queryText)
                )
            )
        )
    )
    .Size(500)
);
answered on Stack Overflow Aug 24, 2020 by Russ Cam

User contributions licensed under CC BY-SA 3.0