[Пошаговый анализ] Elasticsearch Chinese PhraseQuery не может точно соответствовать анализу проблемы

Elasticsearch

Повторение проблемы

  • Во-первых, взгляните на следующий пример и угадайте, могут ли два запроса вызвать doc1
PUT test_phrase
{
  "mappings" : {
      "_doc" : {
        "properties" : {
          "body" : {
            "type" : "text",
            "analyzer" : "ik_max_word",
            "search_analyzer" : "ik_smart"
          }
        }
      }
    }
}

PUT test_phrase/_doc/1
{
  "body":"南京市长"
}

GET test_phrase/_search
{
  "query": {
    "match_phrase": {
      "body": "南京市长"
    }
  }
}

GET test_phrase/_search
{
  "query": {
    "match_phrase": {
      "body": "南京"
    }
  }
}

Причина анализ

  • Так почему? Во-первых, результаты двух психоболов различны, поэтому они прямо подозревают, что не могут найти проблемы, вызванные разными словами.
# GET test_phrase/_analyze
# {
#   "text": ["南京市长"],
#   "analyzer": "ik_max_word"
# }
{
  "tokens" : [
    {
      "token" : "南京",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "CN_WORD",
      "position" : 0
    },
    {
      "token" : "南京市",
      "start_offset" : 0,
      "end_offset" : 3,
      "type" : "CN_WORD",
      "position" : 1
    },
    {
      "token" : "市长",
      "start_offset" : 2,
      "end_offset" : 4,
      "type" : "CN_WORD",
      "position" : 2
    }
  ]
}

# GET test_phrase/_analyze
# {
#   "text": ["南京市长"],
#   "analyzer": "ik_smart"
# }
{
  "tokens" : [
    {
      "token" : "南京",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "CN_WORD",
      "position" : 0
    },
    {
      "token" : "市长",
      "start_offset" : 2,
      "end_offset" : 4,
      "type" : "CN_WORD",
      "position" : 1
    }
  ]
}
  • Так почему же возникает проблема из-за несоответствия в сегментации слов?
  • Разобрав исходный код, мы видим, что общий процесс Phrase выглядит следующим образом.
  • детали следующим образом
    1. org.elasticsearch.index.query.MatchPhraseQueryBuilder#doToQueryПолучив запрос запроса, превратите его в фразовый запрос matchQuery.
    2. org.elasticsearch.index.search.MatchQuery#parseРазобрать запрос и превратить его в запрос lucene
    • вorg.elasticsearch.index.search.MatchQuery#getAnalyzerОпределение словного выключателя, если анализатор запроса не указан, то фраза в использовании поиска «поиск», если не поиска «отеализатор ».
    1. org.apache.lucene.util.QueryBuilder#createFieldQueryВыполните сегментацию слов и определите, есть ли графы и синонимы, если нет, используйте простой фразовый запрос
    2. org.apache.lucene.util.QueryBuilder#analyzePhraseСоздавайте реальные запросы и определяйте позицию каждого слова
    3. org.apache.lucene.search.PhraseWeight#getPhraseMatcherВспомните перевернутую цепочку, затем оцените отстой, если он равен 0, обратитесь к ExactPhraseMatcher
    4. org.apache.lucene.search.ExactPhraseMatcher#nextMatchСравните позиции на равенство

временное решение

  • Из второго шага выше мы видим, что сам ES также предоставляет решение с использованием searchQuoteAnalyzer. Таким образом, временное решение может состоять в том, чтобы позволить пользователю добавлять в текстовое полеsearch_quote_analyzerпараметр,официальная документация search_quote_analyzer
  • Кроме того, если это один сценарий, вы можете указать анализатор или quote_analyzer в строке запроса при запросе.

Решения и трудности

  • Однако позволять пользователям вносить изменения не слишком элегантно, поэтому мы все еще надеемся найти решение на уровне движка. Однако лучшего решения пока не найдено, поэтому временно запишу идеи и внесу дополнения позже.
  • Из вышеприведенного анализа видно, что суть этой проблемы в том, что PhraseQuery определяет, является ли оно коротким предложением, исходя из непрерывности позиции позиции, а из-за разных токенизаторов при записи и запросе позиции несовместимы.
  • Поэтому есть две идеи, но обе они несколько трудны.Я также надеюсь, что мы сможем вам помочь.

Несколько позиций

  • Идея: изменить логику генерации позиции, чтобы сделать запрос и запись согласованными. Напримерik_max_wordВ режиме есть три метода сегментации, и позиция помечается отдельно вместо исходной смешанной метки, чтобы гарантировать, что smart также является подмножеством max
  • Возьмем в качестве примера «Техническое обслуживание моста через реку Янцзы в Нанкине».
    • Текущая смешанная схема ставок:

      Нанкин Нанкин мэр Янцзы Мост через реку Янцзы мост ремонт
      0 1 2 3 4 5 6
    • Независимая схема маркировки:

      Нанкин Нанкин мэр Янцзы Мост через реку Янцзы мост ремонт
      0 - 1 2 - 3 4
      0 - 1 - 2 - 3
      - 0 - 1 - 2 3
      - 0 - - 1 - 2
  • Трудности: Как видно из приведенного выше примера, хотя эта схема может обеспечить согласованность позиций, при наличии неоднозначных слов позиции последующих слов будут совершенно другими, что приведет к большому расширению данных. Если вы используете этот метод, вам нужно найти способ быстро записывать и находить несколько позиций.

Оценка непрерывности смещения

  • Идея: В настоящее время по непрерывности позиции судят о том, короткое ли это предложение, но мы начинаем с_analyzerРезультаты можно увидеть в дополнение кposition,У нас все еще естьstart_offsetиend_offset, которые являются более точными, чем position. Таким образом, вы можете рассмотреть возможность использования согласованности различий смещения для оценки.
  • Трудности: есть два момента, на которые следует обратить внимание: во-первых, смещение, вызванное стоп-словами, является прерывистым, во-вторых, несколько пробелов в слове «new york» также вызовут несогласованность смещения. Кроме того, если вы хотите изменить эту логику, вам нужно изменить lucene, а стоимость обслуживания высока.

использованная литература

  • Elasticsearch 6.6 Исходный код