#elasticsearch #elasticsearch-nested
#elasticsearch #elasticsearch-вложенный
Вопрос:
Я пытаюсь отфильтровать гостиничные номера по ценовому диапазону в эластичном поиске. В номерах установлена цена за ночь по умолчанию, а также могут быть установлены пользовательские цены на определенные дни.
Я сохраняю nightlyPrice
и вложенный объект для пользовательских цен вместе с датами. Сопоставление является smt. Нравится:
{
"adverts": {
"mappings": {
"advert": {
"properties": {
"nightlyPrice": {"type": "float"},
"customPrices": {
"type": "nested",
"properties": {
"date": {"type": "date"},
"price": {"type": "float"}
}
}
}
}
}
}
}
Например, я хочу получить номера в ценовом диапазоне от 100 до 200 долларов в период с 1 по 7 июля.
Итак, я придумал эту логику:
- Либо
customPrices.date
должно быть между 2019-07-01 и 2019-07-07 иcustomPrices.price
между 100 и 200. - или
nightlyPrice
должно быть от 100 до 200, а между 05 и 07 июля неcustomPrices.date
установлено.
Однако я не смог применить эту логику к эластичному поиску, вложенные объекты / запросы, я думаю, довольно сложны.
Это последний запрос, который я придумал:
{
"query": {
"bool": {
"filter": [
{
"term": {
"status": "active"
}
}
],
"must": [
{
"bool": {
"should": [
{
"nested": {
"path": "customPrices",
"query": {
"bool": {
"must": [
{
"range": {
"date": {
"from": "2019-07-01",
"to": "2019-07-07"
}
}
},
{
"range": {
"price": {
"from": 100,
"to": 200
}
}
}
]
}
}
}
},
{
"bool": {
"must": [
{
"range": {
"nightlyPrice": {
"from": 100,
"to": 200
}
}
}
],
"must_not": [
{
"nested": {
"path": "customPrices",
"query": {
"range": {
"customPrices.date": {
"from": "2019-07-01",
"to": "2019-07-07"
}
}
}
}
}
]
}
}
]
}
}
]
}
}
}
Проблема с этим запросом заключается в том, что если пользовательские цены.дата соответствует диапазону дат, он никогда не соответствует документу, независимо от ценового диапазона. Я экспериментировал с ценовым диапазоном от 1 до 100000 долларов, и он по-прежнему не соответствует.
Пытался использовать explain API, чтобы понять, почему конкретный документ не соответствует, но я этого не понимаю, там написано user requested match_none
query, но есть этот should
запрос, поэтому он должен соответствовать вложенному запросу (первому):
{
"_index": "adverts",
"_type": "advert",
"_id": "13867",
"matched": false,
"explanation": {
"value": 0.0,
"description": "Failure to meet condition(s) of required/prohibited clause(s)",
"details": [
{
"value": 0.0,
"description": "no match on required clause ( (ToParentBlockJoinQuery (MatchNoDocsQuery("User requested "match_none" query.")) ( nightlyPrice:[100.0 TO 200.0] -ToParentBlockJoinQuery (customListingPrices.date:[1561939200000 TO 1562543999999]))) #status:active",
"details": [
{
"value": 0.0,
"description": "Failure to meet condition(s) of required/prohibited clause(s)",
"details": [
{
"value": 0.0,
"description": "no match on required clause (ToParentBlockJoinQuery (MatchNoDocsQuery("User requested "match_none" query.")) ( nightlyPrice:[100.0 TO 200.0] -ToParentBlockJoinQuery (customListingPrices.date:[1561939200000 TO 1562543999999])))",
"details": [
{
"value": 0.0,
"description": "No matching clauses",
"details": []
}
]
},
{
"value": 0.0,
"description": "match on required clause, product of:",
"details": [
{
"value": 0.0,
"description": "# clause",
"details": []
},
{
"value": 1.0,
"description": "status:active",
"details": []
}
]
}
]
}
]
},
{
"value": 0.0,
"description": "match on required clause, product of:",
"details": [
{
"value": 0.0,
"description": "# clause",
"details": []
},
{
"value": 1.0,
"description": "DocValuesFieldExistsQuery [field=_primary_term]",
"details": []
}
]
}
]
}
}
Любая помощь или идея приветствуются…
Ответ №1:
Если вы внимательно посмотрите на первое must
предложение, окажется, что вы не указали весь путь к полю.
{
"range":{
"date":{ <-- must be "customPrices.date"
"from":"2019-07-01",
"to":"2019-07-07"
}
}
},
{
"range":{
"price":{ <-- must be "customPrices.price"
"from":100,
"to":200
}
}
}
Ниже показано, каким должен быть запрос, и он должен нормально работать в вашем случае использования.
Запрос
POST <your_index_name>/_search
{
"query":{
"bool":{
"filter":{
"term":{
"status":"active"
}
},
"must":[
{
"bool":{
"should":[
{
"bool":{
"must":[
{
"nested":{
"path":"customPrices",
"query":{
"bool":{
"must":[
{
"range":{
"customPrices.date":{
"gte":"2019-07-01",
"lte":"2019-07-09"
}
}
},
{
"range":{
"customPrices.price":{
"gte":100,
"lte":200
}
}
}
]
}
}
}
}
]
}
},
{
"bool":{
"must":[
{
"range":{
"nightlyPrice":{
"gte":100,
"lte":200
}
}
}
],
"must_not":[
{
"nested":{
"path":"customPrices",
"query":{
"range":{
"customPrices.date":{
"gte":"2019-07-05",
"lte":"2019-07-07"
}
}
}
}
}
]
}
}
]
}
}
]
}
}
}
Надеюсь, это поможет!
Комментарии:
1. привет, @ madpoet, вышеуказанное решило проблему, с которой вы столкнулись. Вы ищете что-то еще?
2. Любопытно, почему у вас есть как
should
, так и amust
вокруг вложенного запроса. Конечно,must
само по себе прекрасно?3. Ну, изначально я думал об этом, но, возможно, у OP должен быть гораздо более сложный запрос, который он не раскрыл. Я только что поделился с ним точным решением, относящимся к проблеме, из-за которой он застрял. Также это зависит от глубины запроса, например, что, если у него есть несколько предложений
should
иmust
на разных глубинах . Возможно, именно поэтому я думаю, что он знает, что делает, и поделился с ним решением, в котором он застрял. Я видел гораздо более сложные запросы на гораздо более глубоких уровнях, и я собираюсь дать ему возможность усомниться в этом.