Spec-Zone.ru › Elasticsearch 7
›Руководство по Elasticsearch [7.17] ›Поиск данных

Выделение фрагментов

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

Выделение фрагментов не отражает булеву логику запроса при извлечении терминов для выделения. Таким образом, для некоторых сложных булевых запросов (например, вложенных булевых запросов, запросов с использованием minimum_should_match и т.д.), части документов могут быть выделены, что не соответствует совпадениям запроса.

Выделение требует фактического содержимого поля. Если поле не хранится (сопоставление не устанавливает store в true), фактическое _source загружается, и соответствующее поле извлекается из _source.

Например, чтобы получить выделения для поля content в каждом результате поиска, используя стандартный выделение, включите объект highlight в тело запроса, который указывает поле content:

GET /_search
{
  "query": {
    "match": { "content": "kimchy" }
  },
  "highlight": {
    "fields": {
      "content": {}
    }
  }
}

Elasticsearch поддерживает три выделения: unified, plain и fvh (быстрое векторное выделение). Вы можете указать выделение type, которое вы хотите использовать для каждого поля.

Единое выделение

Выделение unified использует унифицированное выделение Lucene. Это выделение разбивает текст на предложения и использует алгоритм BM25 для оценки отдельных предложений как документов в корпусе. Оно также поддерживает точное выделение фраз и выделение нескольких терминов (нечеткое, префикс, регулярное выражение). Это стандартное выделение.

Простое выделение

Выделение plain использует стандартное выделение Lucene. Оно пытается отразить логику совпадения запроса в терминах понимания важности слов и критериев позиционирования слов в запросах с фразами.

Выделение plain лучше всего подходит для выделения простых совпадений запроса в одном поле. Чтобы точно отразить логику запроса, оно создает небольшой индекс в оперативной памяти и повторно выполняет исходные критерии запроса через планировщик выполнения запросов Lucene, чтобы получить доступ к информации о совпадениях низкого уровня для текущего документа. Это повторяется для каждого поля и каждого документа, которые нужно выделить. Если вы хотите выделить много полей во многих документах со сложными запросами, мы рекомендуем использовать выделение unified для полей postings или term_vector.

Быстрое векторное выделение

Выделение fvh использует быстрое векторное выделение Lucene. Это выделение может использоваться для полей с term_vector, установленным в with_positions_offsets в сопоставлении. Быстрое векторное выделение:

  • Может быть настраиваемым с помощью boundary_scanner.
  • Требует установки term_vector в with_positions_offsets, что увеличивает размер индекса
  • Может комбинировать совпадения из нескольких полей в один результат. См. matched_fields
  • Может назначать разные веса совпадениям в разных позициях, что позволяет, например, сортировать совпадения фраз выше совпадений по отдельным словам при выделении запроса с усилением, который усиливает совпадения фраз по сравнению с совпадениями по отдельным словам

Выделение fvh не поддерживает запросы span. Если вам нужна поддержка запросов span, попробуйте альтернативное выделение, например, выделение unified.

Стратегия смещений

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

  • Списка постфиксации. Если index_options установлено в offsets в сопоставлении, выделение unified использует эту информацию для выделения документов без повторного анализа текста. Оно повторно выполняет исходный запрос непосредственно на списке постфиксации и извлекает соответствующие смещения из индекса, ограничивая выбор выделенными документами. Это важно, если у вас большие поля, так как это не требует повторного анализа текста для выделения. Это также требует меньше дискового пространства, чем использование term_vectors.
  • Векторные термины. Если информация о векторных терминах предоставляется путем установки term_vector в term_vector в сопоставлении, выделение unified автоматически использует векторные термины для выделения поля. Это быстро, особенно для больших полей (> 1MB) и для выделения многословных запросов, таких как prefix или wildcard, потому что оно может получить доступ к словарю терминов для каждого документа. Выделение fvh всегда использует векторные термины.
  • Простое выделение. Этот режим используется выделением unified, когда нет другой альтернативы. Оно создает небольшой индекс в оперативной памяти и повторно выполняет исходные критерии запроса через планировщик выполнения запросов Lucene, чтобы получить доступ к информации о совпадениях низкого уровня для текущего документа. Это повторяется для каждого поля и каждого документа, требующего выделения. Выделение plain всегда использует простое выделение.

Простое выделение для больших текстов может потребовать значительного времени и памяти. Для защиты от этого максимальное количество символов текста, которые будут анализироваться, ограничено 1000000. Это значение по умолчанию можно изменить для определенного индекса с помощью настройки индекса index.highlight.max_analyzed_offset.

Параметры выделения

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

boundary_chars
Строка, содержащая каждый разделительный символ. По умолчанию .,!? \t\n.
boundary_max_scan
Сколько символов просканировать для поиска разделительных символов. По умолчанию 20.
boundary_scanner

Указывает, как разбить выделенные фрагменты: chars, sentence или word. Действует только для выделений unified и fvh. По умолчанию установлено значение sentence для выделения unified. По умолчанию установлено значение chars для выделения fvh.

chars
Используйте символы, указанные в boundary_chars, в качестве границ выделения. Параметр boundary_max_scan управляет тем, насколько далеко нужно искать символы-разделители. Действует только для выделения fvh.
sentence

Разбивать выделенные фрагменты по границам предложений, определяемым методом Java BreakIterator. Для задания языка можно использовать boundary_scanner_locale.

При использовании с выделением unified, сканер sentence разбивает предложения, длиннее fragment_size, по границам слов рядом с fragment_size. Для того, чтобы никогда не разбивать предложения, можно установить fragment_size в значение 0.

word
Разбивать выделенные фрагменты по границам слов, определяемым методом Java BreakIterator. Для задания языка можно использовать boundary_scanner_locale.
boundary_scanner_locale
Управляет языковым окружением (locale), используемым для поиска границ предложений и слов. Этот параметр принимает тег языка, например, "en-US", "fr-FR", "ja-JP". Более подробная информация доступна в документации Locale Language Tag. Значение по умолчанию — Locale.ROOT.
encoder
Указывает, следует ли кодировать фрагмент HTML: default (без кодирования) или html (HTML-экранировать текст фрагмента, а затем вставить теги выделения)
fields

Указывает поля, для которых нужно получить выделения. Можно использовать шаблоны для задания полей. Например, comment_* для получения выделений для всех полей text, match_only_text и keyword, которые начинаются с comment_.

Выделяются только поля типа text, match_only_text и keyword, если используются шаблоны. Если вы используете пользовательский маппер и хотите выделить поле, вы должны явно указать имя поля.

force_source
Выделение по исходному тексту, даже если поле хранится отдельно. По умолчанию — false.
fragmenter

Указывает, как текст должен быть разделен на фрагменты выделения: simple или span. Действует только для выделения plain. По умолчанию — span.

simple
Разбивает текст на фрагменты одинаковой длины.
span
Разбивает текст на фрагменты одинаковой длины, но старается не разбивать текст между выделенными терминами. Это полезно, когда вы ищете фразы. Значение по умолчанию.
fragment_offset
Управляет отступом, с которого нужно начинать выделение. Действует только при использовании выделения fvh.
fragment_size
Размер фрагмента выделения в символах. По умолчанию — 100.
highlight_query

Выделяет совпадения для запроса, отличного от поискового запроса. Это особенно полезно, если вы используете запрос rescore, так как по умолчанию они не учитываются при выделении.

Elasticsearch не проверяет, что highlight_query содержит поисковый запрос каким-либо образом, поэтому возможно его настроить так, что результаты корректного запроса не будут выделены. В целом, вы должны включить поисковый запрос в состав highlight_query.

matched_fields
Объединяет совпадения по нескольким полям, чтобы выделить одно поле. Это наиболее удобно для многопольных случаев, где один и тот же текст анализируется различными способами. Все matched_fields должны иметь term_vector, установленное на with_positions_offsets, но только поле, для которого объединяются совпадения, загружается, так что только оно получает выгоду от store, установленного на yes. Действует только для выделения fvh.
no_match_size
Количество символов, которые нужно вернуть с начала поля, если нет фрагментов для выделения. По умолчанию 0 (ничего не возвращается).
number_of_fragments
Максимальное количество фрагментов для возврата. Если установлено значение 0, фрагменты не возвращаются. Вместо этого содержимое всего поля выделяется и возвращается. Это может быть полезно, когда требуется выделение коротких текстов, таких как заголовок или адрес, но фрагментация не требуется. Если number_of_fragments равно 0, fragment_size игнорируется. По умолчанию — 5.
order
Сортирует выделенные фрагменты по оценке при значении score. По умолчанию фрагменты выводятся в порядке их появления в поле (order: none). Установка этого параметра в значение score выведет наиболее релевантные фрагменты первыми. Каждый выделение использует свою логику для вычисления оценок релевантности. См. документ Как работают выделения ES в интернете для получения более подробной информации о том, как различные выделения находят лучшие фрагменты.
phrase_limit
Управляет количеством совпадающих фраз в документе, которые рассматриваются. Предотвращает выделение fvh от анализа слишком большого количества фраз и излишнего потребления памяти. При использовании matched_fields, phrase_limit фраз на совпадающее поле рассматриваются. Увеличение лимита увеличивает время запроса и потребляет больше памяти. Поддерживается только выделением fvh. По умолчанию — 256.
pre_tags
Используется совместно с post_tags для определения HTML-тегов, используемых для выделенного текста. По умолчанию выделенный текст заключен в теги <em> и </em>. Укажите в виде массива строк.
post_tags
Используется совместно с pre_tags для определения HTML-тегов, используемых для выделенного текста. По умолчанию выделенный текст заключен в теги <em> и </em>. Укажите в виде массива строк.
require_field_match
По умолчанию выделяются только поля, содержащие совпадение с запросом. Установите require_field_match на false, чтобы выделить все поля. По умолчанию — true.
max_analyzed_offset
По умолчанию максимальное количество символов, анализируемых для запроса выделения, ограничено значением, определенным в настройке index.highlight.max_analyzed_offset. При превышении этого предела возвращается ошибка. Если эта настройка установлена в неотрицательное значение, выделение прекращается на этом максимальном пределе, и остальная часть текста не обрабатывается, следовательно, не выделяется, и не возвращается ошибка. Настройка запроса max_analyzed_offset не переопределяет настройку index.highlight.max_analyzed_offset, которая преобладает, если она установлена в значение ниже, чем настройка запроса.
tags_schema

Установите значение styled для использования встроенной схемы тегов. Схема тегов styled определяет следующие pre_tags и определяет post_tags как </em>.

<em class="hlt1">, <em class="hlt2">, <em class="hlt3">,
<em class="hlt4">, <em class="hlt5">, <em class="hlt6">,
<em class="hlt7">, <em class="hlt8">, <em class="hlt9">,
<em class="hlt10">
type
Выделяемый инструмент: unified, plain или fvh. По умолчанию — unified.

Примеры выделения

  • Изменить глобальные настройки
  • Указать запрос выделения
  • Установить тип выделения
  • Настроить теги выделения
  • Выделить по источнику
  • Выделить все поля
  • Объединение совпадений по нескольким полям
  • Явное упорядочение полей выделения
  • Управление фрагментами выделения
  • Выделение с использованием списка записей
  • Указать фрагментер для простого выделения

Изменить глобальные настройки

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

GET /_search
{
  "query" : {
    "match": { "user.id": "kimchy" }
  },
  "highlight" : {
    "number_of_fragments" : 3,
    "fragment_size" : 150,
    "fields" : {
      "body" : { "pre_tags" : ["<em>"], "post_tags" : ["</em>"] },
      "blog.title" : { "number_of_fragments" : 0 },
      "blog.author" : { "number_of_fragments" : 0 },
      "blog.comment" : { "number_of_fragments" : 5, "order" : "score" }
    }
  }
}

Указать запрос выделения

Вы можете указать highlight_query, чтобы учесть дополнительную информацию при выделении. Например, следующий запрос включает в себя как поисковый запрос, так и запрос рескоринга в highlight_query. Без highlight_query выделение учитывало бы только поисковый запрос.

GET /_search
{
  "query": {
    "match": {
      "comment": {
        "query": "foo bar"
      }
    }
  },
  "rescore": {
    "window_size": 50,
    "query": {
      "rescore_query": {
        "match_phrase": {
          "comment": {
            "query": "foo bar",
            "slop": 1
          }
        }
      },
      "rescore_query_weight": 10
    }
  },
  "_source": false,
  "highlight": {
    "order": "score",
    "fields": {
      "comment": {
        "fragment_size": 150,
        "number_of_fragments": 3,
        "highlight_query": {
          "bool": {
            "must": {
              "match": {
                "comment": {
                  "query": "foo bar"
                }
              }
            },
            "should": {
              "match_phrase": {
                "comment": {
                  "query": "foo bar",
                  "slop": 1,
                  "boost": 10.0
                }
              }
            },
            "minimum_should_match": 0
          }
        }
      }
    }
  }
}

Установить тип выделения

Поле type позволяет принудительно установить определённый тип выделения. Допустимые значения: unified, plain и fvh. Ниже приведён пример, принудительно устанавливающий использование простого выделения:

GET /_search
{
  "query": {
    "match": { "user.id": "kimchy" }
  },
  "highlight": {
    "fields": {
      "comment": { "type": "plain" }
    }
  }
}

Настроить теги выделения

По умолчанию выделенный текст будет обернут в теги <em> и </em>. Это можно настроить, установив pre_tags и post_tags, например:

GET /_search
{
  "query" : {
    "match": { "user.id": "kimchy" }
  },
  "highlight" : {
    "pre_tags" : ["<tag1>"],
    "post_tags" : ["</tag1>"],
    "fields" : {
      "body" : {}
    }
  }
}

При использовании быстрого векторного выделения вы можете указать дополнительные теги, и «важность» будет упорядочена.

GET /_search
{
  "query" : {
    "match": { "user.id": "kimchy" }
  },
  "highlight" : {
    "pre_tags" : ["<tag1>", "<tag2>"],
    "post_tags" : ["</tag1>", "</tag2>"],
    "fields" : {
      "body" : {}
    }
  }
}

Также можно использовать встроенную схему тегов styled:

GET /_search
{
  "query" : {
    "match": { "user.id": "kimchy" }
  },
  "highlight" : {
    "tags_schema" : "styled",
    "fields" : {
      "comment" : {}
    }
  }
}

Выделить по источнику

Принудительно выделяет поля на основе источника, даже если поля хранятся отдельно. По умолчанию значение false.

GET /_search
{
  "query" : {
    "match": { "user.id": "kimchy" }
  },
  "highlight" : {
    "fields" : {
      "comment" : {"force_source" : true}
    }
  }
}

Выделить все поля

По умолчанию выделяются только поля, содержащие совпадение с запросом. Установите require_field_match в false, чтобы выделить все поля.

GET /_search
{
  "query" : {
    "match": { "user.id": "kimchy" }
  },
  "highlight" : {
    "require_field_match": false,
    "fields": {
      "body" : { "pre_tags" : ["<em>"], "post_tags" : ["</em>"] }
    }
  }
}

Объединение совпадений по нескольким полям

Это поддерживается только fvh выделением

Быстрое векторное выделение может объединять совпадения по нескольким полям для выделения одного поля. Это наиболее интуитивно для многопольных анализаторов, которые анализируют одну строку по-разному. Все matched_fields должны иметь term_vector, установленное на with_positions_offsets, но загружается только поле, к которому объединяются совпадения, поэтому только это поле будет извлекать выгоду из store, установленного на yes.

В следующих примерах comment анализируется с помощью анализатора english, а comment.plain анализируется с помощью анализатора standard.

GET /_search
{
  "query": {
    "query_string": {
      "query": "comment.plain:running scissors",
      "fields": [ "comment" ]
    }
  },
  "highlight": {
    "order": "score",
    "fields": {
      "comment": {
        "matched_fields": [ "comment", "comment.plain" ],
        "type": "fvh"
      }
    }
  }
}

Вышеупомянутое совпадение "run with scissors" и "running with scissors", и выделит "running" и "scissors", но не "run". Если обе фразы появляются в большом документе, то "running with scissors" сортируется выше "run with scissors" в списке фрагментов, потому что в этом фрагменте больше совпадений.

GET /_search
{
  "query": {
    "query_string": {
      "query": "running scissors",
      "fields": ["comment", "comment.plain^10"]
    }
  },
  "highlight": {
    "order": "score",
    "fields": {
      "comment": {
        "matched_fields": ["comment", "comment.plain"],
        "type" : "fvh"
      }
    }
  }
}

Вышеупомянутое выделяет "run", а также "running" и "scissors", но всё ещё сортирует "running with scissors" выше "run with scissors", потому что простое совпадение ("running") усилено.

GET /_search
{
  "query": {
    "query_string": {
      "query": "running scissors",
      "fields": [ "comment", "comment.plain^10" ]
    }
  },
  "highlight": {
    "order": "score",
    "fields": {
      "comment": {
        "matched_fields": [ "comment.plain" ],
        "type": "fvh"
      }
    }
  }
}

Вышеупомянутый запрос не выделит "run" или "scissor", но показывает, что не обязательно указывать поле, к которому объединяются совпадения (comment) в совпадающих полях.

Технически также допустимо добавлять поля в matched_fields, которые не делят одну и ту же основную строку с полем, к которому объединяются совпадения. Результаты могут не иметь большого смысла, и если одно из совпадений находится за пределами текста, весь запрос завершится ошибкой.

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

    "highlight": {
        "fields": {
            "comment": {}
        }
    }

чем

    "highlight": {
        "fields": {
            "comment": {
                "matched_fields": ["comment"],
                "type" : "fvh"
            }
        }
    }

Явное упорядочение полей выделения

Elasticsearch выделяет поля в том порядке, в котором они передаются, но согласно спецификации JSON, объекты не упорядочены. Если вам нужно явно указать порядок выделения полей, укажите fields как массив:

GET /_search
{
  "highlight": {
    "fields": [
      { "title": {} },
      { "text": {} }
    ]
  }
}

Ни один из встроенных в Elasticsearch выделений не заботится о порядке выделения полей, но плагин может.

Управление фрагментами выделения

Каждое выделенное поле может управлять размером фрагмента выделения в символах (по умолчанию 100) и максимальным количеством возвращаемых фрагментов (по умолчанию 5). Например:

GET /_search
{
  "query" : {
    "match": { "user.id": "kimchy" }
  },
  "highlight" : {
    "fields" : {
      "comment" : {"fragment_size" : 150, "number_of_fragments" : 3}
    }
  }
}

Помимо этого, можно указать, что фрагменты выделения должны сортироваться по оценке:

GET /_search
{
  "query" : {
    "match": { "user.id": "kimchy" }
  },
  "highlight" : {
    "order" : "score",
    "fields" : {
      "comment" : {"fragment_size" : 150, "number_of_fragments" : 3}
    }
  }
}

Если значение number_of_fragments установлено в 0, фрагменты не генерируются, вместо этого возвращается всё содержимое поля, и, конечно, оно выделяется. Это может быть очень полезно, если необходимо выделить короткие тексты (например, заголовок документа или адрес), но фрагментация не требуется. Обратите внимание, что fragment_size игнорируется в этом случае.

GET /_search
{
  "query" : {
    "match": { "user.id": "kimchy" }
  },
  "highlight" : {
    "fields" : {
      "body" : {},
      "blog.title" : {"number_of_fragments" : 0}
    }
  }
}

При использовании fvh можно использовать параметр fragment_offset для управления отступом, с которого начинается выделение.

В случае отсутствия фрагмента для выделения по умолчанию ничего не возвращается. Вместо этого можно вернуть фрагмент текста с начала поля, установив no_match_size (по умолчанию 0) до длины требуемого текста. Фактическая длина может быть меньше или больше указанной, так как она пытается разбить текст по границам слов.

GET /_search
{
  "query": {
    "match": { "user.id": "kimchy" }
  },
  "highlight": {
    "fields": {
      "comment": {
        "fragment_size": 150,
        "number_of_fragments": 3,
        "no_match_size": 150
      }
    }
  }
}

Выделение с использованием списка записей

Вот пример установки поля comment в схеме индекса, чтобы разрешить выделение с помощью списков записей:

PUT /example
{
  "mappings": {
    "properties": {
      "comment" : {
        "type": "text",
        "index_options" : "offsets"
      }
    }
  }
}

Вот пример установки поля comment для выделения с помощью term_vectors (это увеличит размер индекса):

PUT /example
{
  "mappings": {
    "properties": {
      "comment" : {
        "type": "text",
        "term_vector" : "with_positions_offsets"
      }
    }
  }
}

Указать фрагментер для простого выделения

При использовании plain выделения, вы можете выбрать между simple и span фрагментерами:

GET my-index-000001/_search
{
  "query": {
    "match_phrase": { "message": "number 1" }
  },
  "highlight": {
    "fields": {
      "message": {
        "type": "plain",
        "fragment_size": 15,
        "number_of_fragments": 3,
        "fragmenter": "simple"
      }
    }
  }
}

Ответ:

{
  ...
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1.6011951,
    "hits": [
      {
        "_index": "my-index-000001",
        "_type": "_doc",
        "_id": "1",
        "_score": 1.6011951,
        "_source": {
          "message": "some message with the number 1",
          "context": "bar"
        },
        "highlight": {
          "message": [
            " with the <em>number</em>",
            " <em>1</em>"
          ]
        }
      }
    ]
  }
}
GET my-index-000001/_search
{
  "query": {
    "match_phrase": { "message": "number 1" }
  },
  "highlight": {
    "fields": {
      "message": {
        "type": "plain",
        "fragment_size": 15,
        "number_of_fragments": 3,
        "fragmenter": "span"
      }
    }
  }
}

Ответ:

{
  ...
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1.6011951,
    "hits": [
      {
        "_index": "my-index-000001",
        "_type": "_doc",
        "_id": "1",
        "_score": 1.6011951,
        "_source": {
          "message": "some message with the number 1",
          "context": "bar"
        },
        "highlight": {
          "message": [
            " with the <em>number</em> <em>1</em>"
          ]
        }
      }
    ]
  }
}

Если параметр number_of_fragments установлен в 0, используется NullFragmenter, который вообще не фрагментирует текст. Это полезно для выделения всего содержимого документа или поля.

Как работают выделения внутри

Учитывая запрос и текст (содержимое поля документа), цель выделения — найти лучшие фрагменты текста для запроса и выделить термины запроса в найденных фрагментах. Для этого выделение должно ответить на несколько вопросов:

  • Как разбить текст на фрагменты?
  • Как найти лучшие фрагменты среди всех фрагментов?
  • Как выделить термины запроса в фрагменте?

Как разбить текст на фрагменты?

Соответствующие настройки: fragment_size, fragmenter, type выделения, boundary_chars, boundary_max_scan, boundary_scanner, boundary_scanner_locale.

Простое выделение начинается с анализа текста с помощью заданного анализатора и создания потока токенов из него. Простое выделение использует очень простой алгоритм для разбивки потока токенов на фрагменты. Оно перебирает термины в потоке токенов, и каждый раз, когда конечная позиция текущего термина превышает fragment_size, умноженное на количество созданных фрагментов, создаётся новый фрагмент. Немного больше вычислений выполняется с помощью фрагментирования span, чтобы избежать разделения текста между выделенными терминами. Но в целом, так как разделение выполняется только по fragment_size, некоторые фрагменты могут быть довольно странными, например, начинаться с знака препинания.

Унифицированные или FVH-подсветки лучше разбивают текст на фрагменты, используя возможности Java BreakIterator. Это гарантирует, что фрагмент является полным предложением, если fragment_size позволяет это.

Как найти лучшие фрагменты?

Соответствующие настройки: number_of_fragments.

Для поиска лучших и наиболее релевантных фрагментов подсветка должна оценить каждый фрагмент относительно заданного запроса. Цель – оценить только те термины, которые участвовали в формировании совпадения по документу. Для некоторых сложных запросов эта задача всё ещё находится в стадии разработки.

Простая подсветка создаёт индекс в оперативной памяти из текущего потока токенов и повторно выполняет исходные критерии запроса через планировщик выполнения запросов Lucene для получения доступа к информации о совпадениях низкого уровня для текущего текста. Для более сложных запросов исходный запрос может быть преобразован в запрос с областями, так как запросы с областями могут более точно обрабатывать фразы. Затем эта полученная информация о совпадениях низкого уровня используется для оценки каждого отдельного фрагмента. Метод оценки простой подсветки довольно прост. Каждый фрагмент оценивается по количеству уникальных терминов запроса, найденных в этом фрагменте. Оценка отдельного термина равна его весу, который по умолчанию равен 1. Таким образом, по умолчанию фрагмент, содержащий один уникальный термин запроса, получит оценку 1; фрагмент, содержащий два уникальных термина запроса, получит оценку 2 и так далее. Затем фрагменты сортируются по оценкам, поэтому фрагменты с наивысшими оценками выводятся первыми.

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

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

Как выделить термины запроса во фрагменте?

Соответствующие настройки: pre-tags, post-tags.

Цель – выделить только те термины, которые участвовали в формировании совпадения в документе. Для некоторых сложных булевых запросов эта задача всё ещё находится в стадии разработки, так как подсветки не отражают булеву логику запроса и извлекают только лиственные (термины, фразы, префиксы и т. д.) запросы.

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

FVH и унифицированная подсветка используют промежуточные структуры данных для представления фрагментов в некотором сыром виде, а затем заполняют их фактическим текстом.

Подсветка использует pre-tags, post-tags для кодирования выделенных терминов.

Пример работы унифицированной подсветки

Давайте рассмотрим подробнее, как работает унифицированная подсветка.

Сначала мы создаём индекс с текстовым полем content, который будет индексироваться с помощью анализатора english и будет индексироваться без смещений или векторных представлений терминов.

PUT test_index
{
  "mappings": {
    "properties": {
      "content": {
        "type": "text",
        "analyzer": "english"
      }
    }
  }
}

Мы помещаем следующий документ в индекс:

PUT test_index/_doc/doc1
{
  "content" : "For you I'm only a fox like a hundred thousand other foxes. But if you tame me, we'll need each other. You'll be the only boy in the world for me. I'll be the only fox in the world for you."
}

И мы выполнили следующий запрос с запросом подсветки:

GET test_index/_search
{
  "query": {
    "match_phrase" : {"content" : "only fox"}
  },
  "highlight": {
    "type" : "unified",
    "number_of_fragments" : 3,
    "fields": {
      "content": {}
    }
  }
}

После того, как doc1 найдено как совпадение для этого запроса, это совпадение передаётся унифицированной подсветке для выделения поля content документа. Поскольку поле content не было индексировано ни с смещениями, ни с векторными представлениями терминов, его исходное значение поля будет проанализировано, и в оперативной памяти будет построен индекс из терминов, соответствующих запросу:

{"token":"onli","start_offset":12,"end_offset":16,"position":3},
{"token":"fox","start_offset":19,"end_offset":22,"position":5},
{"token":"fox","start_offset":53,"end_offset":58,"position":11},
{"token":"onli","start_offset":117,"end_offset":121,"position":24},
{"token":"onli","start_offset":159,"end_offset":163,"position":34},
{"token":"fox","start_offset":164,"end_offset":167,"position":35}

Наш сложный фразовый запрос будет преобразован в запрос с областями: spanNear([text:onli, text:fox], 0, true), что означает, что мы ищем термины "onli:" и "fox" в пределах 0 расстояния друг от друга и в заданном порядке. Запрос с областями будет выполнен над созданным ранее индексом в оперативной памяти, чтобы найти следующее совпадение:

{"term":"onli", "start_offset":159, "end_offset":163},
{"term":"fox", "start_offset":164, "end_offset":167}

В нашем примере мы получили одно совпадение, но может быть несколько совпадений. Учитывая совпадения, унифицированная подсветка разбивает текст поля на так называемые «фрагменты». Каждый фрагмент должен содержать как минимум одно совпадение. Унифицированная подсветка с использованием возможностей Java BreakIterator гарантирует, что каждый фрагмент представляет собой полное предложение, пока он не превышает fragment_size. Для нашего примера у нас есть один фрагмент со следующими свойствами (здесь показан только подмножество свойств):

Passage:
    startOffset: 147
    endOffset: 189
    score: 3.7158387
    matchStarts: [159, 164]
    matchEnds: [163, 167]
    numMatches: 2

Обратите внимание, как фрагмент имеет оценку, вычисленную с использованием формулы оценки BM25, адаптированной для фрагментов. Оценки позволяют нам выбрать фрагменты с лучшими оценками, если доступно больше фрагментов, чем требуется пользователем number_of_fragments. Оценки также позволяют нам сортировать фрагменты по order: "score", если этого требует пользователь.

В качестве заключительного шага унифицированная подсветка извлечёт из текста поля строку, соответствующую каждому фрагменту:

"I'll be the only fox in the world for you."

и отформатирует совпадения в этой строке тегами <em> и </em> с использованием информации фрагмента matchStarts и matchEnds:

I'll be the <em>only</em> <em>fox</em> in the world for you.

Этот тип отформатированных строк является конечным результатом подсветки, возвращённым пользователю.

© 2023-2025 Elasticsearch
As of September 2024, Elasticsearch is available under a choice of three licenses: the Server Side Public License (SSPL), the Elastic License, or the AGPLv3 (OSI approved).
Elasticsearch and the Elasticsearch logo are trademarks of Elasticsearch B.V., registered in the U.S. and in other countries.
https://www.elastic.co/guide/en/elasticsearch/reference/7.17/highlighting.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API