Фильтровать запрос по длине вложенных объектов. ie. min_child - PullRequest
0 голосов
/ 03 августа 2020

Я пытаюсь отфильтровать свой запрос по количеству найденных вложенных объектов. В документации Elasti c Search упоминается, что использование сценария - дорогостоящая задача, поэтому я решил сделать это с оценкой, хотя, похоже, я тоже не могу заставить сценарий работать.

Вот мои сопоставления:

"mappings": {
  "properties": {
    "dates" : {
      "type" : "nested",
      "properties" : {
        "rooms" : {
          "type" : "integer"
        },
        "timestamp" : {
          "type" : "long"
        }
      }
    },
    "doc_id" : {
      "type" : "text"
    },
    "distance" : {
      "type" : "integer"
    }
    ...
  }
}

Вот несколько примеров данных:

PUT /test/_doc/1
{
  "doc_id": "1",
  "distance": 1,
  "dates": [
    {
      "rooms": 1,
      "timestamp": 1
    },
    {
      "rooms": 1,
      "timestamp": 2
    },
    ...
  ]
}

Я фильтрую по родительскому полю distance , среди прочего, и фильтрация вложенных dates по их timestamps и rooms. Мне нужно отфильтровать все результаты по точному количеству найденных дат гнезд.

Я пытался позаимствовать из здесь .

Это мой поисковый запрос:

GET /test/_search
{
  "query" : {
    "function_score": {
      "min_score": 20,
      "boost": 1,
      "functions": [
        {
          "script_score": {
            "script": {
                "source": "if (_score > 20) { return - 1; } return _score;"
            }
          }
        }
      ],
      "query": {
        "bool" : {
          "filter": [
            { "range": { "distance": { "lt": 5 }}},
            {
              "nested": {
                "score_mode": "sum",
                "boost": 10,
                "path": "dates",
                "query": {
                  "bool": {
                    "filter": [
                      { "range": { "dates.rooms": { "gte": 1 } } },
                      { "range": { "dates.timestamp": { "lte": 2 }}},
                      { "range": { "dates.timestamp": { "gte": 1 }}}
                    ]
                  }
                }
              }
            }
          ]
        }
      }
    }
  }
}

Это возвращает все совпадающие результаты, но все они имеют оценку 0,0 и не фильтруются по количеству найденных вложенных объектов.

Если это правильное решение, как я могу заставить это работать? Если нет, то как я могу получить скрипт для этого в рамках этого поиска?

Спасибо!

Ответы [ 2 ]

1 голос
/ 08 августа 2020

Прежде чем начать, имейте в виду, что функция оценки изменилась между Elasti c 6 и 7. Вы можете найти обновленные образцы кода на этой этой сущности .

Ваш вопрос не описывает специфику вашего поиска. Читая код, кажется, что вы хотите получить все документы, где расстояние меньше пяти, а количество совпадающих комнат ровно 2. Если это верно, отправленный вами код не позволяет этого достичь.

Причины: ваша оценка функции содержит ваше основное условие и ваше условие относительно количества совпадающих комнат (довольно сложно совместить оба, хотя и не невозможно). Чтобы упростить задачу, изолируйте их, чтобы оценка функции применялась только к количеству комнат.

Предположим, вы используете elasti c 7+, это может сработать:

{
  "_source": {
    "includes": ["*"],
    "excludes": ["dates"]
  },
  "query": {
    "bool": {
      "must": [
        {"range": {"distance": {"lt": 5}}},
        {
          "function_score": {
            "min_score": 20,
            "boost": 1,
            "score_mode": "multiply",
            "boost_mode": "replace",
            "functions": [
              {
                "script_score": {
                  "script": {
                    "source": "if (_score > 20) { return 0; } return _score;"
                  }
                }
              }
            ],
            "query": {
              "nested": {
                "path": "date",
                "boost": 10,
                "score_mode": "sum",
                "query": {
                  "constant_score": {
                    "boost": 1,
                    "filter": {
                      "bool": {
                        "should": [
                          {
                            "bool": {
                              "must": [
                                {"term": {"dates.timestamp": 1}},
                                {"range": {"dates.rooms": {"lt": 5}}}
                              ],
                              "should": [
                                {"term": {"dates.other_prop": 1}},
                                {"term": {"dates.other_prop": 4}}
                              ]
                            }
                          },
                          {
                            "bool": {
                              "must": [
                                {"term": {"dates.timestamp": 2}},
                                {"range": {"dates.rooms": {"lt": 5}}}
                              ],
                              "should": [
                                {"term": {"dates.other_prop": 1}},
                                {"term": {"dates.other_prop": 3}}
                              ]
                            }
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          }
        }
      ]
    }
  }
}
0 голосов
/ 03 августа 2020

Мне удалось заставить все это работать со скорингом, так как фильтрация не позволяет скоринг. Использование GET / test / _explain / [id] помогло точно понять, что происходит

GET /test/_search
{
  // Don't return the nested fields, they are returned in the inner_hits
  "_source": {
    "includes": [ "*" ],
    "excludes": [ "dates" ]
  },
  "query": {
    "function_score": {
      // Score is calculated with 1 point for each matched inner property and outer property.
      // 7 is the exact score to allow
      "min_score": 7,
      "boost": 1,
      "score_mode": "sum",
      "boost_mode": "multiply",
      "functions": [
        {
          "script_score": {
            "script": {
              // Ignore any results that don't match exactly
              "source": "if (_score == 7) { return 1; } return 0;",
              "lang": "painless"
            }
          }
        }
      ],
      "query": {
        "bool" : {
          "must" : [
            { "range" : { "distance" : { "lt": 10 }}},
            {
              "nested": {
                "inner_hits" : {},
                "path": "dates",
                "score_mode": "sum",
                "query": {
                  "bool": {
                    // Match each required nested object individually, then verify with the score if we got 1 match for each should
                    "should": [
                      {
                        "bool": {
                          "must": [
                            { "term": { "dates.timestamp": 1 }},
                            { "range": { "dates.rooms": { "lt": 5 } } }
                          ],
                          "should": [
                            { "term": { "dates.other_prop": 1 }},
                            { "term": { "dates.other_prop": 4 }}
                          ]
                        }
                      },
                      {
                        "bool": {
                          "must": [
                            { "term": { "dates.timestamp": 2 }},
                            { "range": { "dates.rooms": { "lt": 5 } } }
                          ],
                          "should": [
                            { "term": { "dates.other_prop": 1 }},
                            { "term": { "dates.other_prop": 3 }}
                          ]
                        }
                      }
                    ]
                  }
                }
              }
            }
          ]
        }
      }
    }
  }
}
...