首页 > 解决方案 > 嵌套对象中日期时间范围的 Elasticsearch 查询问题

问题描述

嗨,我正在使用 spring data Elasticsearch 来形成查询,并在我的弹性搜索中索引了以下数据

索引数据

[
        {
            "id": "Ef5E-HYB3sZzelDP-ie1",
            "name": "B",
            "availability": [
                {
                    "partial": false,
                    "dates": {
                        "gte": "2020-12-05T09:00:00",
                        "lte": "2020-12-10T13:00:00"
                    }
                }
            ]
        },
        {
            "id": "Ev5F-HYB3sZzelDPIicy",
            "name": "A",
            "availability": [
                {
                    "partial": false,
                    "dates": {
                        "gte": "2020-12-01T07:00:00",
                        "lte": "2020-12-02T12:00:00"
                    }
                }
            ]
        }
    ]

实体

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.date_hour_minute_second)
    private Map<String, LocalDateTime> dates;
}

查询条件:我想查询并检查日期时间之间是否有可用的工作人员:

{
    "startDate": "2020-12-05T09:00:00",
    "endDate": "2020-12-10T10:00:00"
}

为此,我正在使用 bool 查询和嵌套查询创建一个查询,如下所示:

private Query prepareSearchQuery(final WorkerQuery query, Integer pageNumber, Integer pageSize) {
        final BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();

        // To form the nested query
        NestedQueryBuilder nested = prepareAvailabilityQuery(query);

        queryBuilder.must(nested);

        Pageable pageable = PageRequest.of(pageNumber, pageSize);

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

    /**
     * Query to prepare the nested object structure
     * 
     * @param query
     * @return
     */
    private NestedQueryBuilder prepareAvailabilityQuery(final WorkerQuery query) {
        final BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();

        // Add date query
        if (isValidDateTime(query.getStartDate(), query.getStartDate())) { // validate the datetime obj
            // @formatter:off
            RangeQueryBuilder dateQuery = QueryBuilders.rangeQuery("availability.dates")
                    .gte(query.getStartDate())
                    .lte(query.getEndDate())
                    // This is not working with date-time
                    .relation("WITHIN");
            // @formatter:on

            queryBuilder.must(dateQuery);
        }

        return QueryBuilders.nestedQuery("availability", queryBuilder, ScoreMode.None);
    }

对于这种特殊情况,当我注释掉relation("WITHIN")我能够获取查询条件的结果时,但是当查询中包含关系时,它不会返回任何结果。查询有问题吗?

注意:我还添加了转换器以在读取和写入数据时将日期时间转换为 Long 和 Back。

这是供参考的存储库

更新

我更新了我的搜索查询以考虑索引数据的timezoneformat

private NestedQueryBuilder prepareAvailabilityQuery(final WorkerQuery query) {
        final BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        
//      queryBuilder.must(QueryBuilders.termQuery("availability.partial", query.isPartial()));
        
        // Add date query
        if (isValidDateTime(query.getStartDate(), query.getStartDate())) {
            // @formatter:off
            RangeQueryBuilder dateQuery = QueryBuilders.rangeQuery("availability.dates")
                    .gte(query.getFormattedStartDate())
                    .lte(query.getFormattedEndDate())
                    .format("yyyy-MM-dd'T'HH:mm")
                    .timeZone("Asia/Kolkata");
                    // This is not working with date-time
//                  .relation("WITHIN");
            // @formatter:on

            queryBuilder.must(dateQuery);
        }

        return QueryBuilders.nestedQuery("availability", queryBuilder, ScoreMode.None);
    }

所以现在形成的弹性查询对于范围查询来说就像这样:

{
    "range": {
        "availability.dates": {
            "from": "2020-12-01T07:00",
            "to": "2020-12-02T12:00",
            "include_lower": true,
            "include_upper": true,
            "time_zone": "Asia/Kolkata",
            "format": "yyyy-MM-dd'T'HH:mm",
            "boost": 1.0
        }
    }
}

弹性搜索worker索引中的索引映射

{
    "workers": {
        "aliases": {},
        "mappings": {
            "properties": {
                "_class": {
                    "type": "text",
                    "fields": {
                        "keyword": {
                            "type": "keyword",
                            "ignore_above": 256
                        }
                    }
                },
                "availability": {
                    "type": "nested",
                    "properties": {
                        "dates": {
                            "type": "date_range"
                        },
                        "partial": {
                            "type": "boolean"
                        }
                    }
                },
                "name": {
                    "type": "text"
                }
            }
        },
        "settings": {
            "index": {
                "routing": {
                    "allocation": {
                        "include": {
                            "_tier_preference": "data_content"
                        }
                    }
                },
                "refresh_interval": "1s",
                "number_of_shards": "1",
                "provided_name": "workers",
                "creation_date": "1610515965426",
                "store": {
                    "type": "fs"
                },
                "number_of_replicas": "1",
                "uuid": "gJ9zzWs1RXmevJbwwj9Z2g",
                "version": {
                    "created": "7100199"
                }
            }
        }
    }
}

标签: elasticsearchspring-data-elasticsearch

解决方案


推荐阅读