Модуль Similarity
Сходство (модель ранжирования/оценивания) определяет, как оцениваются совпадающие документы. Сходство применяется к каждому полю, что означает, что с помощью отображения можно настроить разное сходство для каждого поля.
Сходство применимо только к полям типа текст и ключевое слово.
Настройка пользовательского сходства считается экспертной функцией, и встроенные сходства, скорее всего, достаточны, как описано в similarity.
Настройка сходства
Большинство существующих или пользовательских сходств имеют параметры настройки, которые можно настроить через параметры индекса, как показано ниже. Параметры индекса можно предоставить при создании индекса или обновлении параметров индекса.
resp = client.indices.create(
index="index",
settings={
"index": {
"similarity": {
"my_similarity": {
"type": "DFR",
"basic_model": "g",
"after_effect": "l",
"normalization": "h2",
"normalization.h2.c": "3.0"
}
}
}
},
)
print(resp) response = client.indices.create(
index: 'index',
body: {
settings: {
index: {
similarity: {
my_similarity: {
type: 'DFR',
basic_model: 'g',
after_effect: 'l',
normalization: 'h2',
"normalization.h2.c": '3.0'
}
}
}
}
}
)
puts response const response = await client.indices.create({
index: "index",
settings: {
index: {
similarity: {
my_similarity: {
type: "DFR",
basic_model: "g",
after_effect: "l",
normalization: "h2",
"normalization.h2.c": "3.0",
},
},
},
},
});
console.log(response); PUT /index
{
"settings": {
"index": {
"similarity": {
"my_similarity": {
"type": "DFR",
"basic_model": "g",
"after_effect": "l",
"normalization": "h2",
"normalization.h2.c": "3.0"
}
}
}
}
} Здесь мы настраиваем сходство DFR, чтобы его можно было использовать как my_similarity в отображениях, как показано в примере ниже:
resp = client.indices.put_mapping(
index="index",
properties={
"title": {
"type": "text",
"similarity": "my_similarity"
}
},
)
print(resp) response = client.indices.put_mapping(
index: 'index',
body: {
properties: {
title: {
type: 'text',
similarity: 'my_similarity'
}
}
}
)
puts response const response = await client.indices.putMapping({
index: "index",
properties: {
title: {
type: "text",
similarity: "my_similarity",
},
},
});
console.log(response); PUT /index/_mapping
{
"properties" : {
"title" : { "type" : "text", "similarity" : "my_similarity" }
}
} Доступные сходства
Сходство BM25 (по умолчанию)
Сходство, основанное на TF/IDF, с встроенной нормализацией tf и, предположительно, работающее лучше для коротких полей (например, имен). Подробнее см. Okapi_BM25. Это сходство имеет следующие параметры:
| | Управляет нелинейной нормализацией частоты терминов (насыщение). Значение по умолчанию — |
| | Управляет степенью нормализации значений tf длиной документа. Значение по умолчанию — |
| | Определяет, игнорируются ли перекрывающиеся токены (токены с приращением позиции 0) при вычислении нормы. По умолчанию это значение true, что означает, что перекрывающиеся токены не учитываются при вычислении норм. |
Имя типа: BM25
Сходство DFR
Сходство, реализующее фреймворк расхождения от случайности. Это сходство имеет следующие параметры:
| | |
| | |
| |
Все параметры, кроме первого, требуют значения нормализации.
Имя типа: DFR
Сходство DFI
Сходство, реализующее модель расхождения от независимости. Это сходство имеет следующие параметры:
| | Возможные значения |
При использовании этого сходства настоятельно рекомендуется не удалять стоп-слова, чтобы получить хорошую релевантность. Также будьте осторожны, что термины, частота которых меньше ожидаемой частоты, получат оценку, равную 0.
Имя типа: DFI
Сходство IB.
Модель, основанная на информации. Алгоритм основан на концепции того, что информационное содержание в любом символическом распределении последовательности в первую очередь определяется повторяющимся использованием его основных элементов. Для письменных текстов эта задача соответствует сравнению стилей письма разных авторов. Это сходство имеет следующие параметры:
| | |
| | |
| | То же, что и в сходстве |
Имя типа: IB
Сходство LM Dirichlet.
Сходство LM Dirichlet. Это сходство имеет следующие параметры:
| | По умолчанию |
Формула оценки в статье присваивает отрицательные оценки терминам, частота которых меньше, чем предсказывается языковой моделью, что недопустимо для Lucene, поэтому таким терминам присваивается оценка 0.
Имя типа: LMDirichlet
Сходство LM Jelinek Mercer.
Сходство LM Jelinek Mercer. Алгоритм пытается захватить важные закономерности в тексте, оставив при этом шум. Это сходство имеет следующие параметры:
| | Оптимальное значение зависит как от коллекции, так и от запроса. Оптимальное значение составляет примерно |
Имя типа: LMJelinekMercer
Скриптированное сходство
Сходство, которое позволяет использовать скрипт для задания способа вычисления оценок. Например, приведенный ниже пример показывает, как переопределить TF-IDF:
resp = client.indices.create(
index="index",
settings={
"number_of_shards": 1,
"similarity": {
"scripted_tfidf": {
"type": "scripted",
"script": {
"source": "double tf = Math.sqrt(doc.freq); double idf = Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0; double norm = 1/Math.sqrt(doc.length); return query.boost * tf * idf * norm;"
}
}
}
},
mappings={
"properties": {
"field": {
"type": "text",
"similarity": "scripted_tfidf"
}
}
},
)
print(resp)
resp1 = client.index(
index="index",
id="1",
document={
"field": "foo bar foo"
},
)
print(resp1)
resp2 = client.index(
index="index",
id="2",
document={
"field": "bar baz"
},
)
print(resp2)
resp3 = client.indices.refresh(
index="index",
)
print(resp3)
resp4 = client.search(
index="index",
explain=True,
query={
"query_string": {
"query": "foo^1.7",
"default_field": "field"
}
},
)
print(resp4) response = client.indices.create(
index: 'index',
body: {
settings: {
number_of_shards: 1,
similarity: {
scripted_tfidf: {
type: 'scripted',
script: {
source: 'double tf = Math.sqrt(doc.freq); double idf = Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0; double norm = 1/Math.sqrt(doc.length); return query.boost * tf * idf * norm;'
}
}
}
},
mappings: {
properties: {
field: {
type: 'text',
similarity: 'scripted_tfidf'
}
}
}
}
)
puts response
response = client.index(
index: 'index',
id: 1,
body: {
field: 'foo bar foo'
}
)
puts response
response = client.index(
index: 'index',
id: 2,
body: {
field: 'bar baz'
}
)
puts response
response = client.indices.refresh(
index: 'index'
)
puts response
response = client.search(
index: 'index',
explain: true,
body: {
query: {
query_string: {
query: 'foo^1.7',
default_field: 'field'
}
}
}
)
puts response const response = await client.indices.create({
index: "index",
settings: {
number_of_shards: 1,
similarity: {
scripted_tfidf: {
type: "scripted",
script: {
source:
"double tf = Math.sqrt(doc.freq); double idf = Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0; double norm = 1/Math.sqrt(doc.length); return query.boost * tf * idf * norm;",
},
},
},
},
mappings: {
properties: {
field: {
type: "text",
similarity: "scripted_tfidf",
},
},
},
});
console.log(response);
const response1 = await client.index({
index: "index",
id: 1,
document: {
field: "foo bar foo",
},
});
console.log(response1);
const response2 = await client.index({
index: "index",
id: 2,
document: {
field: "bar baz",
},
});
console.log(response2);
const response3 = await client.indices.refresh({
index: "index",
});
console.log(response3);
const response4 = await client.search({
index: "index",
explain: "true",
query: {
query_string: {
query: "foo^1.7",
default_field: "field",
},
},
});
console.log(response4); PUT /index
{
"settings": {
"number_of_shards": 1,
"similarity": {
"scripted_tfidf": {
"type": "scripted",
"script": {
"source": "double tf = Math.sqrt(doc.freq); double idf = Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0; double norm = 1/Math.sqrt(doc.length); return query.boost * tf * idf * norm;"
}
}
}
},
"mappings": {
"properties": {
"field": {
"type": "text",
"similarity": "scripted_tfidf"
}
}
}
}
PUT /index/_doc/1
{
"field": "foo bar foo"
}
PUT /index/_doc/2
{
"field": "bar baz"
}
POST /index/_refresh
GET /index/_search?explain=true
{
"query": {
"query_string": {
"query": "foo^1.7",
"default_field": "field"
}
}
} Что дает:
{
"took": 12,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.9508477,
"hits": [
{
"_shard": "[index][0]",
"_node": "OzrdjxNtQGaqs4DmioFw9A",
"_index": "index",
"_id": "1",
"_score": 1.9508477,
"_source": {
"field": "foo bar foo"
},
"_explanation": {
"value": 1.9508477,
"description": "weight(field:foo in 0) [PerFieldSimilarity], result of:",
"details": [
{
"value": 1.9508477,
"description": "score from ScriptedSimilarity(weightScript=[null], script=[Script{type=inline, lang='painless', idOrCode='double tf = Math.sqrt(doc.freq); double idf = Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0; double norm = 1/Math.sqrt(doc.length); return query.boost * tf * idf * norm;', options={}, params={}}]) computed from:",
"details": [
{
"value": 1.0,
"description": "weight",
"details": []
},
{
"value": 1.7,
"description": "query.boost",
"details": []
},
{
"value": 2,
"description": "field.docCount",
"details": []
},
{
"value": 4,
"description": "field.sumDocFreq",
"details": []
},
{
"value": 5,
"description": "field.sumTotalTermFreq",
"details": []
},
{
"value": 1,
"description": "term.docFreq",
"details": []
},
{
"value": 2,
"description": "term.totalTermFreq",
"details": []
},
{
"value": 2.0,
"description": "doc.freq",
"details": []
},
{
"value": 3,
"description": "doc.length",
"details": []
}
]
}
]
}
}
]
}
} Хотя скриптированные сходства обеспечивают большую гибкость, они должны удовлетворять ряду правил. Несоблюдение этих правил может привести к тому, что Elasticsearch будет молча возвращать неправильные лучшие совпадения или сбоям во время поиска с внутренними ошибками:
- Возвращаемые баллы должны быть положительными.
- При всех остальных равных условиях, баллы не должны уменьшаться при увеличении
doc.freq. - При всех остальных равных условиях, баллы не должны увеличиваться при увеличении
doc.length.
Вы могли заметить, что значительная часть вышеприведенного скрипта зависит от статистических данных, которые одинаковы для каждого документа. Можно сделать вышеуказанный код немного эффективнее, предоставив weight_script, которое будет вычислять независимую от документа часть балла и будет доступно через переменную weight. Если weight_script не предоставлено, weight равно 1. weight_script имеет доступ к тем же переменным, что и script, за исключением doc, поскольку оно должно вычислять независимый вклад в балл, связанный с документом.
Нижеприведенная конфигурация даст те же баллы tf-idf, но будет немного эффективнее:
resp = client.indices.create(
index="index",
settings={
"number_of_shards": 1,
"similarity": {
"scripted_tfidf": {
"type": "scripted",
"weight_script": {
"source": "double idf = Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0; return query.boost * idf;"
},
"script": {
"source": "double tf = Math.sqrt(doc.freq); double norm = 1/Math.sqrt(doc.length); return weight * tf * norm;"
}
}
}
},
mappings={
"properties": {
"field": {
"type": "text",
"similarity": "scripted_tfidf"
}
}
},
)
print(resp) response = client.indices.create(
index: 'index',
body: {
settings: {
number_of_shards: 1,
similarity: {
scripted_tfidf: {
type: 'scripted',
weight_script: {
source: 'double idf = Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0; return query.boost * idf;'
},
script: {
source: 'double tf = Math.sqrt(doc.freq); double norm = 1/Math.sqrt(doc.length); return weight * tf * norm;'
}
}
}
},
mappings: {
properties: {
field: {
type: 'text',
similarity: 'scripted_tfidf'
}
}
}
}
)
puts response const response = await client.indices.create({
index: "index",
settings: {
number_of_shards: 1,
similarity: {
scripted_tfidf: {
type: "scripted",
weight_script: {
source:
"double idf = Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0; return query.boost * idf;",
},
script: {
source:
"double tf = Math.sqrt(doc.freq); double norm = 1/Math.sqrt(doc.length); return weight * tf * norm;",
},
},
},
},
mappings: {
properties: {
field: {
type: "text",
similarity: "scripted_tfidf",
},
},
},
});
console.log(response); PUT /index
{
"settings": {
"number_of_shards": 1,
"similarity": {
"scripted_tfidf": {
"type": "scripted",
"weight_script": {
"source": "double idf = Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0; return query.boost * idf;"
},
"script": {
"source": "double tf = Math.sqrt(doc.freq); double norm = 1/Math.sqrt(doc.length); return weight * tf * norm;"
}
}
}
},
"mappings": {
"properties": {
"field": {
"type": "text",
"similarity": "scripted_tfidf"
}
}
}
} Имя типа: scripted
Стандартное сходство
По умолчанию Elasticsearch будет использовать сходство, настроенное как default.
Вы можете изменить стандартное сходство для всех полей в индексе при его создании:
resp = client.indices.create(
index="index",
settings={
"index": {
"similarity": {
"default": {
"type": "boolean"
}
}
}
},
)
print(resp) response = client.indices.create(
index: 'index',
body: {
settings: {
index: {
similarity: {
default: {
type: 'boolean'
}
}
}
}
}
)
puts response const response = await client.indices.create({
index: "index",
settings: {
index: {
similarity: {
default: {
type: "boolean",
},
},
},
},
});
console.log(response); PUT /index
{
"settings": {
"index": {
"similarity": {
"default": {
"type": "boolean"
}
}
}
}
} Если вы хотите изменить стандартное сходство после создания индекса, вы должны закрыть свой индекс, отправить следующий запрос и открыть его снова после этого:
resp = client.indices.close(
index="index",
)
print(resp)
resp1 = client.indices.put_settings(
index="index",
settings={
"index": {
"similarity": {
"default": {
"type": "boolean"
}
}
}
},
)
print(resp1)
resp2 = client.indices.open(
index="index",
)
print(resp2) response = client.indices.close(
index: 'index'
)
puts response
response = client.indices.put_settings(
index: 'index',
body: {
index: {
similarity: {
default: {
type: 'boolean'
}
}
}
}
)
puts response
response = client.indices.open(
index: 'index'
)
puts response const response = await client.indices.close({
index: "index",
});
console.log(response);
const response1 = await client.indices.putSettings({
index: "index",
settings: {
index: {
similarity: {
default: {
type: "boolean",
},
},
},
},
});
console.log(response1);
const response2 = await client.indices.open({
index: "index",
});
console.log(response2); POST /index/_close
PUT /index/_settings
{
"index": {
"similarity": {
"default": {
"type": "boolean"
}
}
}
}
POST /index/_open
© 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/8.17/index-modules-similarity.html