Выделение фрагментов
Выделение фрагментов позволяет получить выделенные фрагменты из одного или нескольких полей в результатах поиска, чтобы показать пользователям, где совпадает запрос. Когда вы запрашиваете выделение, ответ содержит дополнительный элемент 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