Search code examples
elasticsearchspring-data-elasticsearch

Elasticsearch query on array of composite objects along with date ranges


Hi I have a question on how to create an elastic search query for a nested composite object with date ranges and additional field parameters like so

[{
            "name": "A",
            "availability": [
                {
                    "partial": true,
                    "dates": {
                        "gte": "2020-12-01",
                        "lte": "2020-12-02"
                    }
                }
            ]
        },
        {
            "name": "B",
            "availability": [
                {
                    "partial": true,
                    "dates": {
                        "gte": "2020-12-05",
                        "lte": "2020-12-06"
                    }
                },
                {
                    "partial": false,
                    "dates": {
                        "gte": "2020-12-08",
                        "lte": "2020-12-11"
                    }
                }
            ]
        }]

This is my entity data

@Document(indexName = "workers")
public class Worker {
    @Id
    private String id;

    @Field(type = FieldType.Text)
    private String name;

    @Field(type = FieldType.Nested)
    private List<Availability> availability;
}

public class Availability {
    @Field(type = FieldType.Boolean)
    private boolean partial;
    
    @Field(type = FieldType.Date_Range, format = DateFormat.custom, pattern = "uuuu-MM-dd")
    private Map<String, LocalDate> dates;
}


This is the search query that I have currently written, but the results come as empty

         final BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
queryBuilder.must(QueryBuilders.termQuery("availability.partial", query.isPartial()));
         
         RangeQueryBuilder availability = QueryBuilders.rangeQuery("availability.dates")
                   .gte(query.getStartDate())
                   .lte(query.getEndDate());
queryBuilder.must(availability);
        
        Pageable pageable = PageRequest.of(pageNumber, pageSize);

        // @formatter:off
        return new NativeSearchQueryBuilder()
                .withPageable(pageable)
                .withQuery(queryBuilder)
                .build();

This is my query dto

public class WorkerQuery {
    private boolean partial;
    private LocalDate startDate;
    private LocalDate endDate;
}

// Request data
{
    "partial": true,
    "startDate": "2020-12-01",
    "endDate": "2020-12-02"
}


Solution

  • Great start!! You're just missing a nested query since availability is nested. The Java query needs to be like this:

    final BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
    queryBuilder.must(QueryBuilders.termQuery("availability.partial", query.isPartial()));
    
    RangeQueryBuilder availability = QueryBuilders.rangeQuery("availability.dates")
                   .gte(query.getStartDate())
                   .lte(query.getEndDate())
                   .relation("within");
    queryBuilder.must(availability);
    
    final NestedQueryBuilder nested = QueryBuilders.nestedQuery("availability", queryBuilder);
    
    Pageable pageable = PageRequest.of(pageNumber, pageSize);
    
    // @formatter:off
    return new NativeSearchQueryBuilder()
                .withPageable(pageable)
                .withQuery(nested)
                .build();