Получить количество появлений определенного термина в поле поиска - PullRequest
0 голосов
/ 26 марта 2020

У меня есть индекс эластичного поиска (сообщения) со следующими сопоставлениями:

{
    "id": "integer",
    "title": "text",
    "description": "text"
}

Я хочу просто найти число вхождений конкретного термина внутри поля описания для один конкретный документ (у меня есть идентификатор документа и термин для поиска).

например, у меня есть такая запись {id: 123, title: "some title", description: "my city" это LA, это описание поста имеет два вхождения слова city "}.

У меня есть идентификатор документа / идентификатор сообщения для этого сообщения, просто хочу узнать, сколько раз слово "город" встречается в описании для данного сообщения. (результат должен быть 2 в этом случае)

Кажется, не могу найти способ для этого поиска, я не хочу, чтобы вхождения во ВСЕХ документах, но только для одного документа и внутри его одного поля. Пожалуйста, предложите запрос для этого. Спасибо

Elasticsearch Версия: 7.5

1 Ответ

0 голосов
/ 26 марта 2020

Вы можете использовать агрегацию terms на вашем description, но необходимо убедиться, что для него fielddata установлено значение true.

PUT kamboh/
{
  "mappings": {
    "properties": {
      "id": {
        "type": "integer"
      },
      "title": {
        "type": "text"
      },
      "description": {
        "type": "text",
        "fields": {
          "simple_analyzer": {
            "type": "text",
            "fielddata": true,
            "analyzer": "simple"
          },
          "keyword": {
            "type": "keyword"
          }
        }
      }
    }
  }
}

Загрузка образца делает c :

PUT kamboh/_doc/1
{
  "id": 123,
  "title": "some title",
  "description": "my city is LA, this post description has two occurrences of word city "
}

Агрегирование:

GET kamboh/_search
{
  "size": 0,
  "aggregations": {
    "terms_agg": {
      "terms": {
        "field": "description.simple_analyzer",
        "size": 20
      }
    }
  }
}

Выход:

"aggregations" : {
    "terms_agg" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "city",
          "doc_count" : 1
        },
        {
          "key" : "description",
          "doc_count" : 1
        },
        ...
      ]
    }
  }

Теперь, как вы можете видеть, simple анализатор разбить строку на слова и сделать их строчными, но это также избавило от дублирующего города в вашей строке! Я не мог придумать анализатор, который бы сохранял дубликаты ... С учетом сказанного,

Желательно, чтобы эти слова подсчитывались перед индексированием!

Вы бы разбили свою строку через пробел и индексируйте их как массив слов вместо длинной строки.


Это также возможно во время поиска, хотя это очень дорого, плохо масштабируется и вам нужно иметь script.painless.regex.enabled: true в вашем эс.ямле:

GET kamboh/_search
{
  "size": 0,
  "aggregations": {
    "terms_script": {
      "scripted_metric": {
        "params": {
          "word_of_interest": ""
        },
        "init_script": "state.map = [:];",
        "map_script": """
              if (!doc.containsKey('description')) return;

              def split_by_whitespace = / /.split(doc['description.keyword'].value);

              for (def word : split_by_whitespace) {  
                 if (params['word_of_interest'] !== "" && params['word_of_interest'] != word) {
                   return;
                 } 

                 if (state.map.containsKey(word)) {
                   state.map[word] += 1;
                   return;
                 }

                 state.map[word] = 1;
              }
""",
        "combine_script": "return state.map;",
        "reduce_script": "return states;"
      }
    }
  }
}

уступая

...
"aggregations" : {
    "terms_script" : {
      "value" : [
        {
          "occurrences" : 1,
          "post" : 1,
          "city" : 2,  <------
          "LA," : 1,
          "of" : 1,
          "this" : 1,
          "description" : 1,
          "is" : 1,
          "has" : 1,
          "my" : 1,
          "two" : 1,
          "word" : 1
        }
      ]
    }
  }
...
...