Найти точно два слова в любом месте предложения (массив предложений) elastcsearch 6.8 - PullRequest
1 голос
/ 08 октября 2019

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

Поле для поиска выглядит следующим образом:

документ 1

"sentence": [
             "1060 1764 1769 1770 1772 2807 2808 3570", 
             "1101 3402 3403",
             "1101 1764 1769 1770 1772",
             "1001 1060 1099 1100 1101 2806 2807 2808 3570"
            ]

документ 2

"sentence": [
             "1060 2806 2807 2808 3570", 
             "1101 3402 3403",
             "1101 1764 1769 1770 1772",
             "1001 1060 1488 1489 1490 2806 2807 2808 3570"
            ]

Например, при поиске с параметрами "1060 и 1101" он должен возвращать только документ 1, поскольку он содержит оба этих значения водна строкаСтарайтесь не использовать вложенные запросы, если это возможно.

При использовании bool необходимо сопоставлять запросы, сопоставлять запросы фраз, строки запросов, простые строки запросов, bool должен соответствовать запросу фильтра, комбинациям регулярных выражений. Все что-то вернуло, но не совсем то, что мне нужно.

Ответы [ 3 ]

0 голосов
/ 08 октября 2019

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

"sentence": {
    "type": "nested",
        "properties": {
            "sentencearray": {
                "type": "text"
            }
        }
    }

2) запрос с использованием вложенного запроса

{
  "query": {
    "nested": {
      "path": "sentence",
      "query": {
        "bool": {
          "must": [
            { "match": { "sentence.sentencearray": "1060" }},
            { "match": { "sentence.sentencearray":  "1101" }} 
          ]
        }
      }
    }
  }
}

3) Отфильтруйте результат, чтобы сохранить только соответствующий вложенный элемент, добавьте inner_hist в запрос:

{
  "query": {
    "nested": {
      "path": "yourfield",
      "query": {
        "bool": {
          "must": [
            { "match": { "yourfield.yourarray": "1012" }},
            { "match": { "yourfield.yourarray":  "1024" }} 
          ]
        }
      },
      "inner_hits":{}
    }
  }
}
0 голосов
/ 08 октября 2019

Для этого вам не нужен вложенный массив. Вот рабочий пример с соответствием фраз (и большим отрывом!)

# no special mapping needed
PUT stackoverflow-58283078

POST stackoverflow-58283078/_doc
{
  "sentence": [
             "1060 1764 1769 1770 1772 2807 2808 3570", 
             "1101 3402 3403",
             "1101 1764 1769 1770 1772",
             "1001 1060 1099 1100 1101 2806 2807 2808 3570"
            ]
}


POST stackoverflow-58283078/_doc
{
  "sentence": [
    "1060 2806 2807 2808 3570",
    "1101 3402 3403",
    "1101 1764 1769 1770 1772",
    "1001 1060 1488 1489 1490 2806 2807 2808 3570"
  ]
}

POST stackoverflow-58283078/_search
{
  "query": {
    "match_phrase": {
      "sentence": {
        "query":  "1060 1101",
        "slop": 20
      }
    }
  }
}

, этот запрос возвращает:

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.16809675,
    "hits" : [
      {
        "_index" : "stackoverflow-58283078",
        "_type" : "_doc",
        "_id" : "4bsgrG0BWf1JU_OTT9FV",
        "_score" : 0.16809675,
        "_source" : {
          "sentence" : [
            "1060 1764 1769 1770 1772 2807 2808 3570",
            "1101 3402 3403",
            "1101 1764 1769 1770 1772",
            "1001 1060 1099 1100 1101 2806 2807 2808 3570"
          ]
        }
      }
    ]
  }
}

Почему? Потому что при поиске по фразе ищите токены в радиусе «наклонного» токена. Он не совпадает по разным значениям благодаря значению по умолчанию " position_increment_gap ", равному 100.

У вас есть максимальное количество токенов в предложении? Например, если вы хотите обработать 5000 токенов, вы можете настроить откат 5001 (чтобы разрешить инверсию между первым и последним токеном, , поверьте мне, один этот: p ) и position_increment_gap, превосходящий 5002.

0 голосов
/ 08 октября 2019

Источник вашей проблемы в том, что вы на самом деле не понимаете, как массивы работают в упругом, из документов :

нет выделенного типа данных массива.

То есть, когда вы индексируете массив (который не напечатан вложен ), вы теряете возможность запрашивать отдельные элементы в нем из-за того, что упругость "выравнивает" массив.

У вас есть два варианта:

  1. Более правильное решение - переиндексировать ваши данные, составить предложение для ввода вложенный , тогда вы можете запросить каждый элемент по отдельности.

новая структура будет выглядеть примерно так:

            {
                "mappings": {
                    "doc": {
                        "properties": {
                            "sentence": {
                                "type": "nested",
                                "properties": {
                                    "value": {
                                        "type": "text"
                                    }
                                }
                            }
                        }
                    }
                }
            }

Однако, поскольку я не знаком с вашим продуктом и нуждаюсь, возможно, это решение не для вас, так как это может повлиять намногие другие запросы у вас уже работают.

Следовательно, вариант № 2. Используйте scripting для фильтрации документов:

(этот скрипт - быстрый пример, который я вынул, выможет написать более эффективную версиюоптимизировать время выполнения, предполагая, что во многих документах нет ни одного из этих условий, которые вы запрашиваете, было бы целесообразно добавить query (аналогично тому, что вы делали) перед действием filter, чтобы просто выполнить итерации по «подозрительным» совпадениям.)

{
        "query": {
            "bool": {
                 // the must is optional and only here to filter out documents that are not relevant, you should test this on your data to see if its needed.
                 "must": {"query_string": {"default_field": "sentence", "query": "1060 AND 1101"}},
                "filter": {
                    "script": {
                        "script": {
                            "lang": "painless",
                            "source": `                     
                                boolean matched = false;
                                String[] queries = new String[] {'1060', '1101'};
                                for (int i = 0; i < doc['sentence.keyword'].length; i++) {
                                    int count = 0;
                                    for (int j = 0; j < queries.length; j++) {
                                        if (doc['sentence.keyword'][i].indexOf(queries[j]) > -1) {
                                            count += 1;
                                        }
                                    }
                                    if (count === queries.length) {
                                        matched = true;
                                    }
                                }
                                return matched
                                `
                        }
                    }
                }

            }
        }
    }

Как я уже говорил, вариант 2 является менее "правильным" решением и гораздо менее эффективен. но при необходимости он рабочий.

...