相似性模块

edit

相似性(评分/排序模型)定义了如何对匹配的文档进行评分。相似性是按字段定义的,这意味着通过映射可以为每个字段定义不同的相似性。

相似性仅适用于文本类型和关键字类型的字段。

配置自定义相似度被视为一个专家功能,内置的相似度很可能已经足够,如在similarity中所述。

配置相似度

edit

大多数现有的或自定义的相似性算法都有配置选项,可以通过索引设置进行配置,如下所示。这些索引选项可以在创建索引或更新索引设置时提供。

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,如下例所示:

PUT /index/_mapping
{
  "properties" : {
    "title" : { "type" : "text", "similarity" : "my_similarity" }
  }
}

可用的相似性

edit

BM25相似度(默认

edit

基于TF/IDF的相似度,内置了TF归一化,适用于短字段(如名称)。更多详情请参见Okapi_BM25。此相似度具有以下选项:

k1

控制非线性词频归一化(饱和度)。默认值是 1.2

b

控制文档长度对tf值归一化的程度。 默认值是 0.75

discount_overlaps

确定在计算范数时是否忽略重叠标记(位置增量为0的标记)。默认情况下,这是true,意味着在计算范数时重叠标记不计数。

类型名称: BM25

DFR相似性

edit

实现了 随机性分歧框架的相似性。该相似性具有以下选项:

basic_model

可能的值:g, if, inine

after_effect

可能的值:bl

归一化

可能的值:no, h1, h2, h3z

除第一个选项外,所有选项都需要一个归一化值。

类型名称: DFR

DFI相似性

edit

实现了独立性偏差模型的相似性。 该相似性具有以下选项:

independence_measure

可能的值 standardized, saturated, chisquared.

在使用这种相似度时,强烈建议不要去除停用词以获得良好的相关性。同时请注意,频率低于预期频率的词项将获得等于0的分数。

类型名称: DFI

IB相似性。

edit

基于信息内容的模型。该算法基于这样一个概念,即任何符号分布序列中的信息内容主要由其基本元素的重复使用决定。对于书面文本,这一挑战将对应于比较不同作者的写作风格。这种相似性具有以下选项:

分布

可能的值: llspl

lambda

可能的值: dfttf

归一化

DFR相似性中的相同。

类型名称: IB

LM 狄利克雷相似度。

edit

LM Dirichlet 相似度。此相似度具有以下选项:

mu

默认值为 2000

论文中的评分公式对出现次数少于语言模型预测的术语赋予负分,这在Lucene中是不合法的,因此这些术语的得分为0。

类型名称: LMDirichlet

LM Jelinek Mercer 相似度。

edit

LM Jelinek Mercer 相似性。该算法试图捕捉文本中的重要模式,同时忽略噪声。此相似性具有以下选项:

lambda

最佳值取决于集合和查询。对于标题查询,最佳值约为0.1,而对于长查询,最佳值约为0.7。默认为0.1。当值接近0时,匹配更多查询词的文档将比匹配较少词的文档排名更高。

类型名称: LMJelinekMercer

脚本相似性

edit

一种相似性,允许您使用脚本来指定如何计算分数。例如,下面的示例展示了如何重新实现TF-IDF:

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_scriptweight等于1weight_script可以访问与script相同的变量,除了doc,因为它应该计算得分中与文档无关的贡献。

以下配置将给出相同的tf-idf分数,但效率稍高:

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

默认相似度

edit

默认情况下,Elasticsearch 将使用配置为 default 的相似性。

您可以在创建索引时更改索引中所有字段的默认相似度:

PUT /index
{
  "settings": {
    "index": {
      "similarity": {
        "default": {
          "type": "boolean"
        }
      }
    }
  }
}

如果您想在创建索引后更改默认的相似度,您必须关闭您的索引,发送以下请求,并在之后重新打开它:

POST /index/_close

PUT /index/_settings
{
  "index": {
    "similarity": {
      "default": {
        "type": "boolean"
      }
    }
  }
}

POST /index/_open