一、基于词项和基于全文的搜索
- 基于term的查询
term 是表达语义的最小单位,搜索和基于统计的语言模型进行自然语言处理都需要处理term- 在ES中,Term查询,对输入不做分词,会将输入作为一个整体,在倒排索引中查找准确的词项,并使用相关度算分公式为每个包含包含该词项的文档进行算分
- 可以通过Constant score将查询转换成一个Filtering,避免算分,并利用缓存,提高性能
//先存入一些数据
POST /products/_bulk
{ "index": { "_id": 1 }}
{ "productID" : "XHDK-A-1293-#fJ3","desc":"iPhone" }
{ "index": { "_id": 2 }}
{ "productID" : "KDKE-B-9947-#kL5","desc":"iPad" }
{ "index": { "_id": 3 }}
{ "productID" : "JODL-X-1937-#pV7","desc":"MBP" }
POST /products/_search
{
"query": {
"term": {
"desc": {
"value": "iPhone"
//"value":"iphone"
}
}
}
}
//会发现使用“iPhone”检索不出来,只有使用“iphone”才可以检索出来,
//原因就是“desc”字段存入的时候,做了分词,并且转成了小写,用大写的就检索不出来。
//可以使用这种方式先查看分词后的结果,方便检索不到结果时的问题定位
GET _analyze
{
"analyzer": "standard",
"text": ["XHDK-A-1293-#fJ3"]
}
以上这些方法可以针对某个字段做匹配查询,ES默认会给Text类型的字段加上keyword属性,在查询的时候可以采用下面例子给出的这种方式,ES会将包含你要检索词条的所有文档都罗列出来(说白了,就是包含而不相等)。
但是如果想精确查询某个字段,这里给出一个精确查询的解决方案?(下文会给出解决方案)
keyword属性
POST /products/_search
{
"query": {
"term": {
"productID.keyword": { //使用keyword属性就可以精确检索
"value": "XHDK-A-1293-#fJ3"
}
}
}
}
如果不需要相关性计算,可以使用Constant score将查询转换成filter,从而避免相关性算分机制,还能有效利用缓存功能,能够提升效率
POST /products/_search
{
"query": {
"constant_score": { //使用constant_score,转换成filter
"filter": {
"term": {
"productID.keyword":{
"value":"XHDK-A-1293-#fJ3"
}
}
}
}
}
}
- 基于全文的查询
基于全文本的检索- match query
- match phrase
- query string query
查询的时候,会先对输入的查询进行分词,然后每个词项逐个进行底层的查询,最终将结果进行合并,并且为每个文档生成一个算分,输出计算结果。
展示一个布尔查询的demo
//插入数据
POST /products/_bulk
{ "index": { "_id": 1 }}
{ "price" : 10,"avaliable":true,"date":"2018-01-01", "productID" : "XHDK-A-1293-#fJ3" }
{ "index": { "_id": 2 }}
{ "price" : 20,"avaliable":true,"date":"2019-01-01", "productID" : "KDKE-B-9947-#kL5" }
{ "index": { "_id": 3 }}
{ "price" : 30,"avaliable":true, "productID" : "JODL-X-1937-#pV7" }
{ "index": { "_id": 4 }}
{ "price" : 30,"avaliable":false, "productID" : "QQPX-R-3956-#aD8" }
POST products/_search
{
"query": {
"constant_score": {
"filter": {
"bool": {
"must_not":{
"exists":{
"field":"date"
}
}
}
}
}
}
}
Term查询和全文的查询本质区别在于Term不会做分词,而全文查询会对输入进行分词
三、相关性算分
ES 5 之前默认的相关性算分采用TF-IDF,现在采用BM 25
- 词频(Term Frequency) 即检索词在一篇文档中的出现的频率
- 计算方式为:检索词出现的次数/文档的总字数
- 度量一条查询和结果文档相关性的简单算法:将搜索中每一个词的TF相加,即 TF(term1)+TF(term2)+TF(term3)
- Stop word,例如“的”这样的词,对贡献相关度几乎没有帮助,就不应该考虑这些词的TF
- 逆文档频率(Inverse Document Frequency,IDF),即检索词在所有文档中出现的频率
简单的计算公式:log(全部文档数/检索词出现过的文档数),TF-IDF的本质是是将TF求和变成加权求和
举个例子:区块链的应用
出现的文档数 | 总文档数 | IDF | |
---|---|---|---|
区块链 | 200万 | 10亿 | log(500)=8.96 |
的 | 10亿 | 10亿 | log(1)=0 |
应用 | 5亿 | 10亿 | log(2)=1 |
那么“区块链的应用”的TF-IDF相关性计算公式为:
TF(区块链)IDF(区块链)+TF(的)IDF(的)+TF(应用)*IDF(应用)
TF-IDF被公认是信息检索领域最重要的发明,现代的搜索引擎都对TF-IDF进行了细微的优化
ES 可以对索引,字段分别设置boosting参数
//存入数据
PUT testscore/_bulk
{ "index": { "_id": 1 }}
{ "content":"we use Elasticsearch to power the search" }
{ "index": { "_id": 2 }}
{ "content":"we like elasticsearch" }
{ "index": { "_id": 3 }}
{ "content":"The scoring of documents is caculated by the scoring formula" }
{ "index": { "_id": 4 }}
{ "content":"you know, for search" }
//直接查询,会发现"_id"为2的排在前面
POST /testscore/_search
{
"query": {
"match": {
"content": "elasticsearch"
}
}
}
//设置boost的值,会对相关性计算的分数产生影响boost>1 增强,0<boost<1 削弱 ,boost<0 会产生负面影响
POST testscore/_search
{
"query": {
"boosting" : {
"positive" : {
"term" : {
"content" : "elasticsearch"
}
},
"negative" : {
"term" : {
"content" : "like"
}
},
"negative_boost" : 0.2
}
}
}
四、Query Context和Filter Context
在ES中有两种不同的context
- Query context 相关性算分
- Filter context 不需要算分,可以利用cache,获得更好的效能提升
对于多条件组合,可能会组合用到上面两种查询。组合查询中布尔查询又是其中一种常用的查询方式:
must | 必须匹配。贡献算分 |
---|---|
shoud | 选择性匹配。贡献算分 |
must_not | 必须不能匹配。 |
filter | 必须匹配。不贡献算分 |
这里来回答下上文提出的那个不能精确查询的问题
增加一个count字段进行计数
在创建文档的时候,增加一个count字段,在查询的时候通过组合查询的方式,可以解决精确查询的问题
如果标题和描述中都有相同的内容,想要准确检索,也可以采用类似的办法来处理
//title和content里面都有相同的内容
DELETE blogs
POST /blogs/_bulk
{ "index": { "_id": 1 }}
{"title":"Apple iPad", "content":"Apple iPad,Apple iPad" }
{ "index": { "_id": 2 }}
{"title":"Apple iPad,Apple iPad", "content":"Apple iPad" }
//采用下面这种检索方式,就可以按照自己的想法,是选择从title还是content 中检索了。
POST blogs/_search
{
"query": {
"bool": {
"should": [
{"match": {
"title": {
"query": "apple,ipad",
"boost": 1.1
}
}},
{"match": {
"content": {
"query": "apple,ipad",
"boost":0.5
}
}}
]
}
}
}
网友评论