Search code examples
c#elasticsearchnestelasticsearch-querybooleanquery

ElasticSearch: Create should queries from a dynamic list of criterias with NEST


Using ElasticSearch 7.6 I want to find all points which are inside a list of areas. There are several other filter criterias that are added to a list of QueryContainerDescriptors and applied on the final search.

 var queries = new List<Func<QueryContainerDescriptor<MySearchableObject>, QueryContainer>>();

This example works for one area, where Coordinates is a dictionary

foreach (var area in areas)
{
    var pointsList = area.Coordinates.Values.Select(p => new GeoLocation(p.Latitude, p.Longitude)).ToList();

    queries.Add(sqs => sqs
        .GeoPolygon(r => r
            .Field(f => f.Position)
            .ValidationMethod(GeoValidationMethod.Strict)
            .Points(pointsList)));
}

and also this:

queries.Add(sqs => sqs.Bool(b=>b.Should(bs => GeoPolygonShouldQuery(bs, area))));

private static QueryContainer GeoPolygonShouldQuery(QueryContainerDescriptor<MySearchableObject> bs, FilterArea area)
{
     return bs
    .GeoPolygon(r => r
        .Field(f => f.Position)
        .ValidationMethod(GeoValidationMethod.Strict)
        .Points(area.Coordinates.Values.Select(p => new GeoLocation(p.Latitude, p.Longitude))));
}

How would I get around to append a should clause for each area in the list?

Similar to this:

queries.Add(sqs => sqs.Bool(b => b.Should(
                bs => bs.GeoPolygon(r => r.Field(f => f.Position)
                    .Points(areas.ElementAt(0).Coordinates.Values.Select(p => new GeoLocation(p.Latitude, p.Longitude)).ToList())),
                bs => bs.GeoPolygon(r => r.Field(f => f.Position)
                    .Points(areas.ElementAt(1).Coordinates.Values.Select(p => new GeoLocation(p.Latitude, p.Longitude)).ToList()))
                )));

Solution

  • After a bit more trial and error, this seems to solve the issue:

    var areas = FindFilterAreas(query.Areas);
    queries.Add(sqs => sqs.Bool(b => b.Should(MyQueries(b, areas))));
    
    private static List<Func<QueryContainerDescriptor<SearchableSituation>, QueryContainer>> MyQueries(BoolQueryDescriptor<SearchableSituation> qd, IEnumerable<FilterArea> areas)
    {
        List<Func<QueryContainerDescriptor<SearchableSituation>, QueryContainer>> queries = new List<Func<QueryContainerDescriptor<SearchableSituation>, QueryContainer>>();
    
        foreach (var area in areas)
        {
            var pointsList = area.Coordinates.Values.Select(p => new GeoLocation(p.Latitude, p.Longitude)).ToList();
    
            queries.Add(sqs => sqs
                .GeoPolygon(r => r
                    .Field(f => f.Position)
                    .ValidationMethod(GeoValidationMethod.Strict)
                    .Points(pointsList))
            );
        }
    
        return queries;
    }