概述
ES作为一款搜索引擎,搜索结果如何排序,即什么条目或内容更靠前,是一个很核心的问题。排序通常是通过计算语料库中的文档和用户查询之间的相关性或相似度评分来进行。
相似性(得分/排名模型)定义匹配文档如何进行评分。相似性是针对字段的,意味着通过映射可以对每个字段定义不同的相似性模块。
ES有一个内置的相关性评分计算模块,称为相似度模块。ES 5之前,相似度模块一直使用TF-IDF作为它的默认相似度函数。后继版本使用BM25(它是TF-IDF的变更版本)作为默认的相似度函数。
除这两个外,ES支持以下相似度函数:
- DFR
- DFI
- IB
- LM Dirichlet
- LM Jelinek Mercer
- 脚本
算法/模型
布尔模型
BIR,看属性是否含有某词(term)。bool查询遵循越多命中越好原则,文档最终得分是should和must中每个子句的得分累加。filter和must_not属于过滤查询不贡献得分。
TF-IDF
即:词频/逆向文档频率,Term Frequency-Inverse Document Frequency的缩写,文本分析和NLP(自然语言处理)中常用于计算单词之间相似度的函数。TF-IDF通过将词频(Term Frequency)和反向文档频率(Inverse Document Frequency)相乘来工作。前者词频,是给定单词在文档中出现的次数。后者逆向文档频率,是对单词在语料库中的罕见程度进行评分的一种计算。单词越罕见,其得分就越高。
反向文档频率,或叫逆向文档频率,公式:
l
o
g
(
N
d
f
)
log(frac{N}{df})
log(dfN),其中N是语料库中的文档数,df是包含某个单词的文档数。某个单词在语料库中越罕见,其计算评分就越高。
TF-IDF公式:
T
F
∗
l
o
g
(
N
d
f
)
TF*log(frac{N}{df})
TF∗log(dfN),其中TF即为词频的缩写,某个单词在文档中出现的次数。
TF-IDF的问题:没有考虑文档的长度、词频并不饱和。
向量空间模型
向量空间模型,Vector Space Model,简称VSM,提供一种比较多词查询的方式,单个评分代表文档与查询的匹配程度。模型将文档和查询都以向量(vectors)的形式表示。因为向量之间是可以比较的,只要计算待查询向量和文档向量之间的角度就可以得到每个文档的相关度。
VSM里每个数字都代表一个词的权重,与TF/IDF计算方式类似。TF/IDF是VSM计算词权重的默认方式,但不是唯一方式。ES还有其他模型如Okapi-BM25。TF/IDF作为默认算法,因为它是个经检验过的简单又高效的算法,可以提供高质量的搜索结果。
constant_score查询
在constant_score查询中可包含查询或过滤,为任意一个匹配的文档指定评分1,忽略TF/IDF信息:
GET /_search
{
"query": {
"bool": {
"should": [
{
"constant_score": {
"boost": 2,
"query": {
"match": {
"description": "wifi"
}
}
}
},
{
"constant_score": {
"query": {
"match": {
"description": "wife"
}
}
}
}
]
}
}
}
通过boost来配置权重值。最终的评分并不是所有匹配语句的简单求和, 协调因子(coordination factor)和查询归一化因子(query normalization factor)仍然会被考虑在内。
BM25
源自概率相关模型(probabilistic relevance model)
Okapi BM25,同样使用词频、逆向文档频率以及字段长归一化,其计算公式有点吓人:
l
n
(
1
+
d
o
c
C
o
u
n
t
−
f
(
q
i
)
+
服务器托管
0.5
f
(
q
i
)
+
0.5
)
∗
f
(
q
i
,
D
)
f
(
q
i
,
D
)
+
k
1
∗
(
1
−
b
+
b
∗
f
i
e
l
d
L
e
n
a
v
g
F
i
e
l
d
L
e
n
)
ln(1+frac{docCount-f(q_i)+0.5}{f(q_i)+0.5})*frac{f(q_i, D)}{f(q_i, D)+k1*(1-b+b*frac{fieldLen}{avgFieldLen})}
ln(1+f(qi)+0.5docCount−f(qi)+0.5)∗f(qi,D)+k1∗(1−b+b∗avgFieldLenfieldLen)f(qi,D)
其中,k1默认为1.2,b默认为0.75。
BM25有一个比较好的特性就是它提供两个可调参数:
- k1:控制词频结果在词频饱和度中的上升速度。值越小饱和度变化越快,值越大饱和度变化越慢
- b:控制着字段长归一值所起的作用,
b=0.0
会禁用归一化,b=1.0
启用完全归一化。
关于如何在markdown文档里添加数学公式,可参考MarkDown基础及表格、KaTeX公式、矩阵、流程图、UML图、甘特图语法。
实战
配置
大多数已经存在或自定义的相似性拥有配置选项,可以通过索引设置进行配置。当创建索引或更新索引设置时,可以提供索引选项:
"similarity": {
"my_similarity": {
"type": "DFR",
"basic_model": "g",
"after_effect": "l",
"normalization": "h2",
"normalization.h2.c": "3.0"
}
}
然后需要在映射中引用自定义相似性模块:
{
"book": {
"properties": {
"title": {
"type": "string",
"similarity": "my_similarity"
}
}
}
}
ES提供如下几个相似性模块:
- 默认相似性模块基于TF/IDF模式,其他可用选项如下:
discount_overlaps:决定重叠词元(词元的位置增量为0)是否要被忽略。默认为true,意味着重叠词元不会被统计。
类型名:default。 - BM25相似性模块:基于TF/IDF的相似性模块拥有内置的tf标准并且对短字段(如名字)效率更高。类型名:BM25。拥有下列参数:
- k1:控制非线性索引词频率标准(饱和度)
- b:控制文档长度标准化到tf值的程度
- discount_overlaps:决定重叠词元(词元的位置增量为0)是否要被忽略。默认为true,意味着重叠词元不会被统计。
- DFR相似性模块:实现随机性框架的分支。类型名:DFR。拥有下列参数:
- basic_model:可选值:be、d、g、if、in、ine和p
- after_effect:可选值:no、b和l
- normalization:可选值:no、h1、h2、h3和z
- IB相似性模块:基于信息的模式。算法基于设想,信息内容是任何通过基本元素的重复使用产生的符号分布序列。对于书面文本,这个方式会对比不同作者的写作风格。类型名:IB。拥有下面的选项:
- distribution:可选值:ll和spl
- lambda:可选值:df和ttf
- normalization:和DFR相似模块相同
- LM Dirichlet相似性模块:类型名LMDirichlet。拥有这些选项:mu:默认为2000。
- LM Jelinek Mercer相似性模块:这个算法视图捕捉文本中的重要样品。类型名:LMJelinekMercer。拥有下面选项:lambda:最佳值取决于采集和查询。标题查询的最佳值大约是0.1,长查询的最佳值是0.7。当值接近于0,匹配更多查询索引词的文档会比匹配较少索引词的文档的排列位置更靠前。
- 默认和基础相似性模块:默认情况下,ES会使用任何配置为default的相似性模块。然而,相似性方法
queryNorm()
和coord()
不是每个字段都会执行。因此,对于专家用户想要改变这两种方法的实现,不会更改default,可以用base名来配置相似性。然后,相似性会用于这两种方法。
可在elasticsearch.yml
中添加如下配置,修改默认的相似性模块,此配置是对所有字段生效:
index.similarity.default.type: BM25
more_like_this
见名知意。先构建一个索引库包含title和desc两个字段:
PUT /search_data
{
"mappings": {
"properties": {
"title": {
"type": "text",
"term_vector": "yes"
},
"desc": {
"type": "text"
}
}
}
}
term_vector:term_vector为yes时会索引terms向量,加快相似度计算的速度;desc字段未配置term_vector也可以进行more_like_this
查询的,但性能不佳。
查询语句:
GET /_search
{
"query": {
"more_like_this" : {
"fields" : ["title", "desc"],
"like" : "清明节春游踏青春季旅游学校春游亲子游企业郊游活动",
"min_term_freq" : 1,
"max_query_terms" : 12
}
}
}
解释:
- fields:要执行查询的字段,目前只支持text和term
- like:要查询相似的文本,可以是文档id或者一个查询字句
- min_term_freq:最小词频率,低于该频率的词将被忽略
- max_query_terms:查询个数,提取like中文本term的TF-IDF值最大的几个,其余的词将被忽略
如果like文本太长,也可基于文章Id进行相似推荐:
GET /_search
{
"query": {
"more_like_this" : {
"fields" : ["title", "desc"],
"like" : [
{
"_index" : "search_data",
服务器托管 "_id" : "1"
}
],
"min_term_freq" : 1,
"max_query_terms" : 12
}
}
}
like后面是数组,可配置多篇文章。_index
对应的索引库也可以不是当前查询的索引库。
既然有like表示相似,不难猜到ES也会提高unlike字段表示不相似,用于排除有瑕疵的查询数据:
"unlike": [
{
"_index" : "search_data",
"_id" : "1270715"
},
"不应该出现的敏感数据"
],
其它可选参数
-
min_doc_freq
:最小的文档频率,默认为5 -
max_doc_freq
:最大文档频率 -
min_word_length
:单词最小长度 -
max_word_length
:单词最大长度 -
stop_words
:停用词列表 - analyzer:分词器
-
minimum_should_match
:文档应该匹配的最小单词数量,默认为query分词后词项的30% -
boost_terms
:词项权重 - include:是否把输入文档作为结果返回
- boost:整个query的权重,默认为1.0
进阶
explain
ES提供explain API可以查看用于评分计算的每个值,以及它所使用的公式。结果有个boost参数,可以增加或减少相应单词的评分。boost有两种类型:索引时boost(index-time boost)(已弃用)和查询时boost(query-time boost)。
分片
如果查询只使用带有1个分片的索引,则评分结果是一致且可预测的。不同的分片设置会影响ES中的评分计算。当ES计算一个文档的评分时,它只能访问这个分片中的其他文档。公式中IDF和avgLen的值在不同分片之间是不一样。
可使用?search_type=dfs_query_then_fetch
告诉ES在计算评分之前从每个分片中检索所需的值,不过这会显著降低搜索速度。
参考
- ES内容相似性推荐
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
1.把端口port: 15672改成p服务器托管ort:5672 2:virtual-host: my_vhost一定对应上 服务器托管,北京服务服务器托管器托管,服务器租用 http://www.fwqtg.net