Вложенный запрос Elasticsearch с доступными значениями в диапазоне

#elasticsearch #elasticsearch-5 #elasticsearch-dsl

#elasticsearch #elasticsearch-5 #elasticsearch-dsl

Вопрос:

Попытка создать запрос для таких документов, как:

 {
    "name" : "Bob",
    "grades" : [
        {
            "year" : 2010,
            "grade": 8,  
        },
        {
            "year" : 2018,
            "grade": 7,  
        },
        {
            "year" : 2019,
            "grade": 4,  
        }
    ]
},
{
    "name" : "Alice",
    "grades" : [
        { 
            "year" : 2005,
            "grade": 3,  
        },
        {
            "year" : 2016,
            "grade": 8,  
        },
        {
            "year" : 2018,
            "grade": 7,  
        },
        {
            "year" : 2019,
            "grade": 6,  
        }
    ]
}
  

У меня есть диапазон лет, например, с 2010 по 2020 год. Запрос должен возвращать документ, если для всех доступных лет (в документе) в диапазоне (с 2010 по 2020 год) оценки> 5. Если есть оценки <= 5 за пределами интересующего диапазона лет, нам все равно, и это никоим образом не должно повлиять на конечный результат. Таким образом, в основном должен быть возвращен только документ с Алисой. Изучив документацию Elasticsearch, не могу найти решение (скорее всего, я просто что-то пропустил). Я могу создать запрос, если в годах нет пробелов, но в моем случае есть пробелы. Поэтому мой запрос просто отбрасывает такие документы. Текущий запрос:

 {
    "query": {
        "bool": {
            "must": [
                {
                    "nested": {
                        "query": {
                            "bool": {
                                "must": [
                                    {
                                        "term": {
                                            "grades.year": {"value": 2010}
                                        }
                                    },
                                    {
                                        "range": {
                                            "grades.grade": {"from": 5}
                                        }
                                    }
                                ]
                            }
                        },
                        "path": "grades"
                    }
                },
                {
                    "nested": {
                        "query": {
                            "bool": {
                                "must": [
                                    {
                                        "term": {
                                            "grades.year": {"value": 2011}
                                        }
                                    },
                                    {
                                        "range": {
                                            "grades.grade": {"from": 5}
                                        }
                                    }
                                ]
                            }
                        },
                        "path": "grades"
                    }
                },
                ....
            ]
        }
    }
}
  

Возможно, я определенно что-то пропустил. Возможно ли это?

Обновить

Я добавил 2005 год с оценкой 3 к оценкам Алисы. Итак, теперь Алиса все еще должна быть сопоставлена, поскольку 2005 год находится за пределами интересующего диапазона.

Спасибо!

Ответ №1:

Вы можете использовать must_not предложение, которое исключит все документы, содержащие оценку меньше или равную 5

Поисковый запрос:

 {
  "query": {
    "bool": {
      "must": [
        {
          "nested": {
            "path": "grades",
            "query": {
              "bool": {
                "must": [
                  {
                    "range": {
                      "grades.year": {
                        "gte": 2010,
                        "lte": 2020
                      }
                    }
                  }
                ]
              }
            }
          }
        }
      ],
      "must_not": {
        "nested": {
          "path": "grades",
          "query": {
            "bool": {
              "must": [
                {
                  "range": {
                    "grades.grade": {
                      "lte": 5
                    }
                  }
                }
              ]
            }
          }
        }
      }
    }
  }
}
  

Результат поиска:

 "hits": [
      {
        "_index": "64882747",
        "_type": "_doc",
        "_id": "2",
        "_score": 1.0,
        "_source": {
          "name": "Alice",
          "grades": [
            {
              "year": 2016,
              "grade": 8
            },
            {
              "year": 2018,
              "grade": 7
            },
            {
              "year": 2019,
              "grade": 6
            }
          ]
        }
      }
    ]
  

Комментарии:

1. Спасибо! Это действительно полезно и почти делает то, что мне нужно. Но, по-видимому, он удаляет документ, если хотя бы один год имеет класс lte 5. Если есть год, который находится за пределами интересующего диапазона, нас не должно волновать, является ли класс lte 5. Я обновил свой вопрос. Спасибо!

2. @Zanas_x3 но год 2005 находится за пределами диапазона, и grade он также меньше, чем 5 , тем не менее, вы хотите, чтобы этот Alice документ соответствовал?

3. Именно так. Нас интересуют только оценки, которые находятся в диапазоне [2010, 2020]. Если оценка была меньше 5 давным-давно, нам действительно все равно. Я отредактирую свой вопрос, чтобы быть более понятным, извините за путаницу. Спасибо!

4. @Zanas_x3 спасибо за ваш ответ 🙂 Позвольте мне посмотреть, смогу ли я найти способ реализовать ваш вариант использования

5. Спасибо, Бхавья! Вы помогли мне, указав правильный путь. Взгляните на мое решение, похоже, оно делает то, что должно. Надеюсь…

Ответ №2:

Похоже, я нашел решение! Спасибо @Bhavya за то, что направил меня. В основном используется некоторая дополнительная логическая логика. В итоге я получил следующий запрос:

 {
    "query": {
        "bool": {
            "must": [
                {
                    "nested": {
                        "path": "grades",
                        "query": {
                            "bool": {
                                "must": [
                                    {
                                        "range": {
                                            "grades.year": {
                                                "gte": 2010,
                                                "lte": 2020
                                            }
                                        }
                                    }
                                ]
                            }
                        }
                    }
                }
            ],
            "must_not":   {
                "nested": {
                    "path": "grades",
                    "query": {
                        "bool": {
                            "should": [
                                {
                                    "bool": {
                                        "must": [
                                            {
                                                "term": {
                                                    "grades.year": {
                                                        "value": 2010
                                                    }
                                                }
                                            },
                                            {
                                                "range": {
                                                    "grades.grade": {
                                                        "lte": 5
                                                    }
                                                }
                                            }
                                        ]
                                    }
                                },
                                ...
                                ...
                                ...
                                ...
                                ...
                            ]
                        }
                    }
                }
            }
        }
    }
}