Запрос Elasticsearch для массива составных объектов вместе с диапазонами дат

Привет, у меня есть вопрос о том, как создать эластичный поисковый запрос для вложенного составного объекта с диапазонами дат и дополнительными параметрами поля, например

[{
            "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"
                    }
                }
            ]
        }]

Это мои данные сущности

@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;
}


Это поисковый запрос, который я сейчас написал, но результаты пусты.

         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();

Это мой запрос 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"
}


person Sandeep K Nair    schedule 12.01.2021    source источник


Ответы (1)


Отличное начало!! Вам просто не хватает nested запроса, так как availability это nested. Запрос Java должен быть таким:

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();
person Val    schedule 12.01.2021
comment
Ты спасаешь жизнь @Val :) Теперь все работает как положено. Но у меня есть один вопрос по запросу, который вы сформировали выше. Обязательно ли, чтобы запрос nested был корневым объектом запроса? Можно ли это применить только к вложенному объекту availability? - person Sandeep K Nair; 12.01.2021
comment
Я добавил его в корень, потому что у вас нет других ограничений. Если бы вы добавили ограничение в поле worker, вам понадобился бы корневой логический запрос, и вложенный запрос стал бы его компонентом вместе с новым ограничением в рабочем поле верхнего уровня. - person Val; 12.01.2021
comment
Понял :) Большое спасибо за предоставленную информацию - person Sandeep K Nair; 12.01.2021
comment
Круто, дайте мне знать, если это сработает! - person Val; 12.01.2021
comment
Привет @Val, я обновил свой запрос здесь Дайте мне знать, правильно ли я делаю? - person Sandeep K Nair; 12.01.2021
comment
Это выглядит правильно. Ты пытался? - person Val; 12.01.2021
comment
Я попытался запросить его, и, похоже, он возвращает результаты. Но одна вещь, которую я нашел странной в запросе, это, скажем, если я делаю этот запрос - startDate of 2020-12-02 and endDate of 2020-12-05 я получаю результаты как Worker A, так и Worker B. Но логически это не должно происходить правильно, так как мы ищем даты между проиндексированными датами, которые недоступны. - person Sandeep K Nair; 12.01.2021
comment
Хм, да, я пропустил часть .relation("contains") (по умолчанию это intersect). Смотрите мой обновленный ответ - person Val; 12.01.2021
comment
Я обновил код, добавив .relation("contains"), и теперь результаты вообще не отображаются :( - person Sandeep K Nair; 12.01.2021
comment
Не возражаете ли вы обновить код в своем репо? - person Val; 12.01.2021
comment
Делал это уже. Также я попробовал .relation("WITHIN"), и это, кажется, работает. Это правильно, кстати? - person Sandeep K Nair; 12.01.2021
comment
Да, это наоборот, within — правильное отношение, хороший улов! - person Val; 12.01.2021
comment
Понял :) Спасибо за помощь, ценю. - person Sandeep K Nair; 12.01.2021
comment
Круто, рад, что смог быть полезен! - person Val; 12.01.2021
comment
Привет, @val, у меня был еще один дополнительный вопрос/проблема, основанный на импровизациях, которые я делал с тем же кодом. Могу ли я задать это здесь или я должен создать еще один вопрос? :) - person Sandeep K Nair; 12.01.2021
comment
Всегда лучше формулировать вопросы кратко, поэтому, когда на них будет дан ответ, создайте новый. Спасибо за понимание ;-) - person Val; 12.01.2021
comment
вот ссылка на вопрос stackoverflow.com/questions/65691864/ - person Sandeep K Nair; 12.01.2021