1 query和filter区别
在进行query的时候,除了完成匹配的过程,我们实际上在问"这个结果到底有多匹配我们的搜索关键词"。在所有的返回结果的后面都会有一个_score
字段表示这个结果的匹配程度,也就是相关性。相关性越高的结果就越排在前面,相关性越低就越靠后。当两个文档的相关性相同的时候,会根据lucene内部的doc_id
字段来排序,这个字段对于用户是不可见的也不能控制。
而在进行filter的时候,仅仅是在问"这个文档符是否符合要求",这仅仅是一个过滤的操作判断文档是否满足我们的筛选要求,不会计算任何的相关性。比如timestamp
的范围是否在2019和2020之间,status
状态是否是1等等。
在一个查询语句里面可以同时存在query
和filter
,只不过只有query
的查询字段会进行相关性_score
的计算,而filter
仅仅用来筛选。比如在下面的查询语句里面,只有title
字段会进行相关性的计算,而下面的status
只是为了筛选并不会计算相关性。
GET /_search
{
"query": {
"bool": {
"must": [
{"match": {"title": "Search"}}
],
"filter": [
{"term": {"state": 1}}
]
}
}
}
对于在实际应用中应该用query
还是用filter
需要根据实际的业务场景来看。如果你的产品的搜索只是需要筛选得到最后的搜索结果并不需要Elasticsearch的相关性排序(你可能自定义了其他的排序规则),那么使用filter
就完全能够满足要求并且能够有更好的性能(filter
不需要计算相关性而且会缓存结果);如果需要考虑文档和搜索词的相关性,那么使用query
就是最好的选择。
2 相关性
Elasticsearch的相似度计算主要是利用了全文检索领域的计算标准——TF/IDF(Term Frequency/Inverted Document Frequency)也就是检索词频率和反向文档频率
- TF(检索词频率):检索词在这个字段里面出现的频率越高,相关性越高。比如搜索词出现5次肯定比出现1次的文档相关性更高。
- IDF(反向文档频率):包含检索词的文档的频率越高,这个检索词的相关性比重越低。如果一个检索词在所有的文档里面都出现了,比如中文的
的
,那么这个检索词肯定就不重要,相对应的根据这个检索词匹配的文档的相关性权重应该下降。 - 字段长度:注意这个字段是文档的里面被搜索的字段,不是检索词。如果这个字段的长度越长,相关性就越低。这个主要是因为这个检索词在字段内的重要性降低了,文档就相对来说不那么匹配了。
在复合查询里面,比如bool
查询,每个子查询计算出来的评分会根据特定的公式合并到综合评分里面,最后根据这个综合评分来排序。当我们想要修改不同的查询语句的在综合评分里面的比重的时候,可以在查询字段里面添加boost
参数,这个值是相对于1
来说的。如果大于1
则这个查询参数的权重会提高;如果小于1
,权重就下降。
这个评分系统一般是系统默认的,我们可以根据需要定制化我们自己的相关性计算方法,比如通过脚本自定义评分。
3 分词器
分析器是针对text
字段进行文本分析的工具。文本分析是把非结构化的数据(比如产品描述或者邮件内容)转化成结构化的格式从而提高搜索效率的过程,通常在搜索引擎里面应用的比较多。
text
格式的数据和keyword
格式的数据在存储和索引的时候差别比较大。keyword
会直接被当成整个字符串保存在文档里面,而text
格式数据,需要经过分析器解析之后,转化成结构化的文档再保存起来。比如对于the quick fox
字符串,如果使用keyword
类型,保存直接就是the quick fox
,使用the quick fox
作为关键词可以直接匹配,但是使用the
或者quick
就不能匹配;但是如果使用text
保存,那么分析器会把这句话解析成the
、quick
、fox
三个token进行保存,使用the quick fox
就无法匹配,但是单独用the
、quick
、fox
三个字符串就可以匹配。所以对于text
类型的数据的搜索需要格外注意,如果你的搜索词得不到想要的结果,很有可能是你的搜索语句有问题。
分析器的工作过程大概分成两步:
- 分词(Tokenization):根据停止词把文本分割成很多的小的token,比如
the quick fox
会被分成the
、quick
、fox
,其中的停止词就是空格,还有很多其他的停止词比如&
或者#
,大多数的标点符号都是停止词 - 归一化 (Normalization):把分隔的token变成统一的形式方便匹配,比如下面几种
- 把单词变成小写,
Quick
会变成quick
- 提取词干,
foxes
变成fox
- 合并同义词,
jump
和leap
是同义词,会被统一索引成jump
Elasticsearch自带了一个分析器,是系统默认的标准分析器,使用标准分析器, 大多数情况下都能够有不错的分析效果。用户也可以定义自己的分析器,用于满足不同的业务需求。
想要知道某个解析器的分析结果,可以直接在ES里面进行分析,执行下面的语句就行了:
POST /_analyze
{
"analyzer": "standard",
"text": "1 Fire's foxes"
}
返回的结果是:
{
"tokens" : [
{
"token" : "1",
"start_offset" : 0,
"end_offset" : 1,
"type" : "<NUM>",
"position" : 0
},
{
"token" : "fire's",
"start_offset" : 2,
"end_offset" : 8,
"type" : "<ALPHANUM>",
"position" : 1
},
{
"token" : "fox",
"start_offset" : 9,
"end_offset" : 12,
"type" : "<ALPHANUM>",
"position" : 2
}
]
}
返回的tokens
内部就是所有的解析结果,token
表示解析的词语部分,start_offset
和end_offset
分别表示token在原text内的起始和终止位置,type
表示类型,position
表示这个token在整个tokens列表里面的位置。