很多写说明文档,没有总结写开头。因为文档内容又很多,你看到后面就忘记前面,没有形成结构化知识。这样知识在大脑里是离散的,不完整,不准确的。
所以我的文章都是把结论写最开始,或者要说的全部内容用一句话写在最开始。你知道了可以不用看,不知道,可以一眼知道接下来学到什么。
当你看到后面,不记得前面了,回到最开始一句话,大脑就会统领全局,形成最准确和系统性的知识。
我们只能按大脑习惯的学习知识,不可违背大脑的习惯学习,不然只会事倍功半,甚至于学过就忘。
本文说是es的查询,分为:Query查询
和Filter查询、
复合查询、聚合查询。
Query context 查询上下文
这种语句在执行时既要计算文档是否匹配,还要计算文档相对于其他文档的匹配度有多高,匹配度越高,_score
分数就越高
Filter context 过滤上下文
过滤上下文中的语句在执行时只关心文档是否和查询匹配,不会计算匹配度,也就是得分。
一、query查询
也就是你写dsl(es 查询语法语言)语句时,可以用的下一级字段例如 {"query":{"match":{}}}
1、match查询
match query
: 知道分词器的存在,会对filed进行分词操作,然后再查询match_all
: 查询所有文档multi_match
: 可以指定多个字段match_phrase
: 短语匹配查询,ElasticSearch引擎首先分析(analyze)查询字符串,从分析后的文本中构建短语查询,这意味着必须匹配短语中的所有分词。
#1、 查询年龄为3的(命中:ID = 1)
GET student/_search
{
"query":{
"match":{"age": 3}
}
}
#2、查询兴趣里包含'演戏'的 (命中 ID = 2,5,4)
GET student/_search
{
"query":{
"match":{"interests": "演戏"}
}
}
#这里只要interests包含'演戏','演','戏'的都会命中
#3、查询索引所有文档 (命中 ID = 1,2,3,4,5)
GET student/_search
{
"query":{
"match_all": {}
}
}
#4、查询name和address包含'德' (命中 ID = 2)
GET student/_search
{
"query":{
"multi_match": {
"query": "德",
"fields":["name","address"]
}
}
}
#说明 这里文档ID为4的address为'德州',应该也包含'德',但却没有被命中,原因是我们索引结构中,address属性是一个keyword类型,它是需要完全匹配,而不是包含的关系。
#如果这里query为'德州'就可以命中2条数据。
#5、查询兴趣里包含'演员'的 (命中 无)
GET student/_search
{
"query":{
"match_phrase":{"interests": "演员"}
}
}
# 这里和match的区别是这里是真正包含'演员',而不是只要满足其中一个字就会被模糊命中
2、term查询和terms查询
term query
: 会去倒排索引中寻找确切的term,它并不知道分词器的存在。这种查询适合keyword 、numeric、date。
term
:查询某个字段为该关键词的文档(它是相等关系而不是包含关系)
terms
:查询某个字段里含有多个关键词的文档
#1、查询地址等于'香港'的文档 (命中:ID = 2,5)
GET student/_search
{
"query":{
"term":{ "address":"香港"}
}
}
#如果仅检索'香'那是无法命中的,因为keyword需要完全匹配才能命中
#2、查询地址等于"香港"或"北京"的 (命中: ID =2,3,5)
GET student/_search
{
"query":{
"terms":{
"address":["香港","北京"]
}
}
}
3、 范围查询
range
: 实现范围查询
include_lower
: 是否包含范围的左边界,默认是true
include_upper
: 是否包含范围的右边界,默认是true
#2、查询年纪18到28 (命中 ID = 2,3)
GET student/_search
{
"query": {
"range": {
"age": {
"from": 18,
"to": 28,
"include_lower": true,
"include_upper": true
}
}
}
}
4、wildcard查询
允许使用通配符* 和 ?来进行查询*
代表0个或多个字符?
代表任意一个字符
#1、查询姓名'徐'开头的 (命中 ID = 1)
GET student/_search
{
"query": {
"wildcard": {
"name": "徐*"
}
}
}
5、fuzzy实现模糊查询
模糊查询可以在Match和 Multi-Match查询中使用以便解决拼写的错误,模糊度是基于Levenshteindistance计算与原单词的距离。使用如下:
GET student/_search
{
"query": {
"fuzzy": {
"interests": {
"value": "演"
}
}
}
}
二、Filter查询
filter是不计算相关性的,同时可以cache。因此,filter速度要快于query
。
#1、获取年龄为3的 (命中 ID = 1)
GET student/_search
{
"post_filter":{
"term":{"age": 3}
}
}
#2、查询年纪为3或者63的 (命中 ID = 1,4)
GET student/_search
{
"post_filter":{
"terms":{"age":[3,63]}
}
}
三、复合查询
有:bool query
(布尔查询)、boosting query
(提高查询)、constant_score
(固定分数查询)、dis_max
(最佳匹配查询)、function_score
(函数查询)
1.布尔查询 "query":"bool"
# must: 必须匹配。贡献算分
# must_not:过滤子句,必须不能匹配,但不贡献算分
# should: 选择性匹配,至少满足一条。贡献算分
# filter: 过滤子句,必须匹配,但不贡献算分 在filter元素下指定的查询对评分没有影响 , 评分 返回为0。分数仅受已指定查询的影响。
POST _search
{
"query": {
"bool" : {
"must" : {
"term" : { "user" : "kimchy" }
},
"filter": {
"term" : { "tag" : "tech" }
},
"must_not" : {
"range" : {
"age" : { "gte" : 10, "lte" : 20 }
}
},
"should" : [
{ "term" : { "tag" : "wow" } },
{ "term" : { "tag" : "elasticsearch" } }
],
"minimum_should_match" : 1,
"boost" : 1.0
}
}
}
2、提高查询 boosting query
在上面的复合查询我们可以通过must_not+must
先剔除不想匹配的文档,再获取匹配的文档,但是有一种场景就是我并不需要完全剔除,而是把需要剔除的那部分文档的分数降低。
# 通过Boosting的方式,将3的记录也纳入结果集,只是排名会靠后。(结果 1->2->3)
POST news/_search
{
"query": {
"boosting": {
"positive": {
"match": {
"content": "apple"
}
},
"negative": {
"match": {
"content": "pie"
}
},
"negative_boost": 0.5
}
}
}
"""
说明boosting需要搭配三个关键字 positive , negative , negative_boost
只有匹配了 positive查询 的文档才会被包含到结果集中,但是同时匹配了negative查询 的文档会被降低其相关度,通过将文档原本的_score和negative_boost参数进行
相乘来得到新的_score。因此,negative_boost参数一般小于1.0。在上面的例子中,任何包含了指定负面词条的文档的_score都会是其原本_score的一半。
"""
就是说就算文档包含了苹果,但因为包含了树或者水果那么我们也会过滤这条文档信息,因为我们要查的苹果公司相关信息,如果你是苹果树那对我来讲确实是不匹配,
所以直接过滤掉,看是没啥问题。
但是你想,这样做是不是太粗暴了,因为一个文档中包含'苹果'和'树'那不代表一定是苹果树,而可能是 '苹果公司组织员工一起去种树' 那么这条文档理应出现
而不是直接过滤掉,所以我们就可以用boosting query。就像上面这个例子一样。
3、最佳匹配
dis_max
: 只是取分数最高的那个query的分数而已。
GET /_search
{
"query": {
"dis_max" : {
"queries" : [
{ "term" : { "title" : "Quick pets" }},
{ "term" : { "body" : "Quick pets" }}
],
"tie_breaker" : 0.7
}
}
}
"""
假设一条文档的'title'查询得分是 1,'body'查询得分是1.6。那么总得分为:1.6+1*0.7 = 2.3。
如果我们去掉"tie_breaker" : 0.7 ,那么tie_breaker默认为0,那么这条文档的得分就是 1.6 + 1*0 = 1.6
"""
四、function_score(函数查询)
向量搜索的计算余弦相似度,就可以用到
{
"query": {
"script_score": {
"query": {
"bool":{"must":[{"match": {"org_id": org_id}},
{"match": {"type_": type_}},
{"match": {"bot_id": bot_id}}],
"filter": {"exists": {"field": "sentence_vec"}}
}
},
"script": {
"source": "cosineSimilarity(params.queryVector, 'sentence_vec')+1.0",
"params": {
"queryVector": sentence_vector
}
}
}
}
}