(5)elasticsearch的Query DSL

官网连接:
https://www.elastic.co/guide/en/elasticsearch/reference/7.10/query-filter-context.html

Query DSL(Domain Specific Language)

  • query string search
  • 全文检索-fulltext search
  • 精准匹配-term match
  • 过滤器-filter
  • 组合查询-bool query

1 查询上下文

​ 使用query关键字进行检索,倾向于相关度搜索,故需要计算评分。搜索是Elasticsearch最关键和重要的部分。

GET product/_search
#这两个的查询是等效的
GET product/_search
{
  "query": {
    "match_all": {}
  }
}

2 相关度评分:_score

​ 概念:相关度评分用于对搜索结果排序,评分越高则认为其结果和搜索的预期值相关度越高,即越符合搜索预期值。在7.x之前相关度评分默认使用TF/IDF算法计算而来,7.x之后默认为BM25。在核心知识篇不必关心相关评分的具体原理,只需知晓其概念即可。

​ 排序:相关度评分为搜索结果的排序依据,默认情况下评分越高,则结果越靠前。

GET product/_search
{
  "query": {
    "match": {
      "name": "xiaomi"
    }
  }
}
结果:可以看到_score是倒序的
{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.72615415,
    "hits" : [
      {
        "_index" : "product",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 0.72615415, 
        "_source" : {
          "name" : "xiaomi erji",
          "desc" : "erji zhong de huangmenji",
          "price" : 999,
          "tags" : [
            "low",
            "bufangshui",
            "yinzhicha"
          ]
        }
      },
      {
        "_index" : "product",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.60996956,
        "_source" : {
          "name" : "xiaomi nfc phone", 
          "desc" : "zhichi quangongneng nfc,shouji zhong de jianjiji",
          "price" : 4999,
          "tags" : [
            "xingjiabi",
            "fashao",
            "gongjiaoka"
          ]
        }
      }
    ]
  }
}

3 元数据:_source

  1. 禁用_source:

    1. 好处:节省存储开销

    2. 坏处:

      • 不支持update、update_by_query和reindex API。
      • 不支持高亮。
      • 不支持reindex、更改mapping分析器和版本升级。
      • 通过查看索引时使用的原始文档来调试查询或聚合的功能。
      • 将来有可能自动修复索引损坏。

      总结:如果只是为了节省磁盘,可以压缩索引比禁用_source更好。

  2. 数据源过滤器:

    Including:结果中返回哪些field

    Excluding:结果中不要返回哪些field,不返回的field不代表不能通过该字段进行检索,因为元数据不存在不代表索引不存在

    1. 在mapping中定义过滤:支持通配符,但是这种方式不推荐,因为mapping不可变

      PUT product2
      {
        "mappings": {
          "_source": {
            "includes": [
              "name",
              "price"
            ],
            "excludes": [
              "desc",
              "tags"
            ]
          }
        }
      }
      PUT /product2/_doc/1
      {
        "name": "hongmi erji",
        "desc": "erji zhong de kendeji",
        "price": 399,
        "tags": ["lowbee","xuhangduan","zhiliangx"]
      }
      GET product2/_search
      #结果,只展示了name\price
      
    2. 常用过滤规则

      • “_source”: “false”,
      • “_source”: “obj.*”,
      • “_source”: [ “obj1.*”, “obj2.*” ],
      • “_source”: {
        “includes”: [ “obj1.*”, “obj2.*” ],
        “excludes”: [ “*.description” ]
        }
      DELETE product2
      PUT /product2/_doc/1
      {
        "owner":{
          "name":"zhangsan",
          "sex":"男",
          "age":18
        },
        "name": "hongmi erji",
        "desc": "erji zhong de kendeji",
        "price": 399,
        "tags": ["lowbee","xuhangduan","zhiliangx"]
      }
      GET product2/_search
      GET product2/_search
      {
        "_source": false,  #查询结果,不显示_source
        "_source": "name",
        "_source": "owner",
        "_source": "owner.*",
        "_source": "owner.name",
        "_source": ["owner.name","owner.age"],
        #如果includes和excludes没有交集,此时查询结果只显示name\price,查询结果以includes为准,此时owner属性是没有写到excludes里边的,此时excludes不写也是可以的
        #如果includes和excludes有了交集,如excludes里边也有name,此时查询结果只显示price
        "_source": {
          "includes": [ 
            "name",
            "price"
          ],
          "excludes": [
            "desc",
            "tags"
          ]
        },
        "query": {
          "match_all": {}
        }
      }
      

4 query string search

#查询所有
GET /product/_search
#带参数,name里边包含xiaomi的
GET /product/_search?q=name:xiaomi
#分页
GET /product/_search?from=0&size=2&sort=price:asc

#在每条数据里边加入date字段
#精准匹配 exact value,只会匹配date为2021-06-01的数据
GET /product/_search?q=date:2021-06-01

#_all搜索 相当于在所有有索引的字段中检索(默认都是创建了倒排索引),会匹配内容包含2021-06-01的数据,结果为date\desc里有2021-06-01的数据
GET /product/_search?q=2021-06-01

#我们不想匹配desc里的怎么办?把它的索引关掉
#1.删掉product
DELETE product
#2.创建索引映射,关掉desc的索引
PUT product
{
  "mappings": {
    "properties": {
      "desc": {
        "type": "text", 
        "index": false
      }
    }
  }
}
#3.插入还是刚才的那些数据
#4.再次查询,结果只有date的数据
GET /product/_search?q=2021-06-01

#恢复原来的数据,删掉product、插入还是刚才的那些数据
#发现查询到了desc里边包含01的数据,而没有date的数据,说明desc的数据被分词了
GET /product/_search?q=01

DELETE product
PUT /product/_doc/1
{
    "name" : "xiaomi phone",
    "desc" :  "shouji zhong de zhandouji",
    "date": "2021-06-01",
    "price" :  3999,
    "tags": [ "xingjiabi", "fashao", "buka" ]
}
PUT /product/_doc/2
{
    "name" : "xiaomi nfc phone",
    "desc" :  "zhichi quangongneng nfc,shouji zhong de jianjiji",
    "date": "2021-06-02",
    "price" :  4999,
    "tags": [ "xingjiabi", "fashao", "gongjiaoka" ]
}
PUT /product/_doc/3
{
    "name" : "nfc phone",
    "desc" :  "shouji zhong de hongzhaji",
    "date": "2021-06-03",
    "price" :  2999,
    "tags": [ "xingjiabi", "fashao", "menjinka" ]
}
PUT /product/_doc/4
{
    "name" : "xiaomi erji",
    "desc" :  "erji zhong de huangmenji",
    "date": "2021-04-15",
    "price" :  999,
    "tags": [ "low", "bufangshui", "yinzhicha" ]
}
PUT /product/_doc/5
{
    "name" : "hongmi erji",
    "desc" :  "erji zhong de kendeji 2021-06-01",
    "date": "2021-04-16",
    "price" :  399,
    "tags": [ "lowbee", "xuhangduan", "zhiliangx" ]
}

5 全文检索-fulltext search

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cSJj1ZUr-1682735356029)(01-核心知识篇.assets/image-20230415123708817.png)]

用户请求会被分词

  • match:匹配包含某个term的子句

  • match_all:匹配所有结果的子句

  • multi_match:多字段条件

  • match_phrase:短语查询,

#DSL
#match ,请求会被分词,分成了xiaomi、phone词相
#包含 xiaomi 或者 phone 的结果都会被命中
GET product/_search
{
  "query": {
    "match": {
      "name": "xiaomi phone"
    }
  }
}
#match_all,查询所有数据
GET product/_search
{
  "query": {
    "match_all": {}
  }
}
#multi_match,在fields字段里边包含了query
#name中包含了phone 或 huangmenji
#desc中包含了phone 或 huangmenji
#where a=xx or b=xx
GET product/_search
{
  "query": {
    "multi_match": {
      "query": "phone huangmenji",
      "fields": ["name","desc"]
    }
  }
}
#match_phrase
#这里的短语不会被分词,必须包含 xiaomi 和 nfc 两个词项,并且顺序还要相同,并且两个词项之间不能包含其他词项。注意 短语查询并不是直接包含 xiaomi nfc 这个短语
GET product/_search
{
  "query": {
   "match_phrase": {
     "name": "xiaomi nfc"
   }
  }
}

6 精准匹配-term match

  • term:匹配和搜索词项完全相等的结果

  • term和match_phrase区别:

    match_phrase 会将检索关键词分词, match_phrase的分词结果必须在被检索字段的分词中都包含,而且顺序必须相同,而且默认必须都是连续的

    term搜索不会将搜索词分词

  • term和keyword区别

    term是对于搜索词不分词,

    keyword是字段类型,是对于source data中的字段值不分词

  • terms:匹配和搜索词项列表中任意项匹配的结果

  • range:范围查找

#没结果
GET product/_search
{
  "query": {
    "term": {
      "name": "xiaomi phone"
    }
  }
}
#有结果。被检索字段里必须包含这里的每一个词项,且顺序一致,
GET product/_search
{
  "query": {
    "match_phrase": {
      "name": "xiaomi phone"
    }
  }
}
#有结果
GET product/_search
{
  "query": {
    "term": {
      "name.keyword": "xiaomi phone"
    }
  }
}
#查询tags里边包含lowbee\gongjiaoka
GET product/_search
{
  "query": {
    "terms": {
      "tags": [
        "lowbee",
        "gongjiaoka"
      ]
    }
  }
}
#gt是>,gte是>=,lt是<,lte是<=
GET product/_search
{
  "query": {
    "range": {
      "price": {
        "gte": 399,
        "lte": 2999
      }
    }
  }
}
GET product/_search
{
  "query": {
    "range": {
      "date": {
        "gte": "2021-04-15",
        "lte": "2021-04-16"
      }
    }
  }
}
#date里边也可以加时区
#now-1d/d 当前时间减一天,单位是天
#now/d 当前时间,单位是天
GET product/_search
{
  "query": {
    "range": {
      "date": {
        "gte": "now-1d/d", 
        "lte": "now/d" 
      }
    }
  }
}

7 过滤器-filter

GET _search
{
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "status": "active"
        }
      }
    }
  }
}

query和filter的主要区别在: filter是结果导向的而query是过程导向。

query倾向于“当前文档和查询的语句的相关度”,而filter倾向于“当前文档和查询的条件是不是相符”。即在查询过程中,query是要对查询的每个结果计算相关性得分的(_score,倒序的),而filter不会。另外filter有相应的缓存机制,可以提高查询效率。

例子,比如查询10万数据,按照age排序,不使用filter的时候,是按照_score倒序的;可以使用filter先把数据过滤出来,之后再排序。

#_score,倒序的
GET product/_search
{
  "query": {
    "term": {
      "name": "phone"
    }
  }
}
#_score固定的,没有给定的话就是1.0,可以使用boost给定分数
GET product/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "name": "phone"
        }
      },
      "boost": 1.2
    }
  }
}
#bool里边也可以嵌套filter
GET product/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "name": "phone"
          }
        }
      ]
    }
  }
}

8 组合查询-bool query

bool:可以组合多个查询条件,bool查询也是采用more_matches_is_better的机制,因此满足must和should子句的文档将会合并起来计算分值

  • must:必须满足子句(查询)必须出现在匹配的文档中,并将有助于得分。
  • filter:过滤器 不计算相关度分数,cache☆子句(查询)必须出现在匹配的文档中。但是不像 must查询的分数将被忽略。Filter子句在filter上下文中执行,这意味着计分被忽略,并且子句被考虑用于缓存。
  • should:可能满足 or子句(查询)应出现在匹配的文档中。
  • must_not:必须不满足 ,不计算相关度分数 not子句(查询)不得出现在匹配的文档中。子句在过滤器上下文中执行,这意味着计分被忽略,并且子句被视为用于缓存。由于忽略计分,0因此将返回所有文档的分数。

minimum_should_match:参数指定should返回的文档必须匹配的子句的数量或百分比。如果bool查询包含至少一个should子句,而没有must或 filter子句,则默认值为1。否则,默认值为0

#must计算出来的_score是不一样的,倒序
#查询name包含xiaomi\phone,且desc包含shouji zhong
GET product/_search
{ 
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "xiaomi phone"
          }
        },
        {
          "match_phrase": {
            "desc": "shouji zhong"
          }
        }
      ]
    }
  }
}

#filter计算出来的_score都是0.0
#查询name包含xiaomi\phone,且desc包含shouji zhong
GET product/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "match": {
            "name": "xiaomi phone"
          }
        },
        {
          "match_phrase": {
            "desc": "shouji zhong"
          }
        }
      ]
    }
  }
}

#must_not计算出来的_score都是0.0
#查询name包含xiaomi\nfc,且price>=500 的对立面
GET product/_search
{
  "query": {
    "bool": {
      "must_not": [
        {
          "match": {
            "name": "xiaomi nfc"
          }
        },
        {
          "range": {
            "price": {
              "gte": 500
            }
          }
        }
      ]
    }
  }
}

#should
#相当于or,查询条件就是可以满足0个,1个,多个
GET product/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match_phrase": {
            "name": "xiaomi nfc"
          }
        },
        {
          "range": {
            "price": {
              "lte": 500
            }
          }
        }
      ]
    }
  }
}

#组合查询
#单独用must结果是1、2、4
#单独用filter结果是4、5
#must+filter结果4(交集是4)
#must与filter是 and 的关系
#为什么不把filter的条件写在must里边呢?
#must是要进行相关度分数计算的。先在filter中进行过滤(此时是不进行相关度分数的计算的),之后再用must。filter减少了计算,而且有缓存
GET product/_search
{ 
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "xiaomi"
          }
        }
      ],
      "filter": [
        {
          "range": {
            "price": {
              "lte": 1000
            }
          }
        }
      ]
    }
  }
}

#单独用should结果是1、2、3、4、5
#单独用filter结果是2、3
#should+filter结果1、2、3、4、5
#因为此时should子句可以满足的数量是0,
#此时设置minimum_should_match为1,表示should子句可以满足的数量是1,执行结果就是2、3了
#可以多加几个should子句
#should子句里边也可以再包含bool子句
GET product/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "range": {
            "price": {
              "lte": 10000
            }
          }
        }
      ],
      "should": [
        {
          "match_phrase": {
            "name": "nfc phone"
          }
        }
      ]
    }
  }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个使用elasticsearch_dsl的示例代码: ```python # 引入必要的包 from elasticsearch_dsl import connections, Search from elasticsearch import Elasticsearch # 连接到elasticsearch es = connections.create_connection(hosts=["127.0.0.1:9200"], timeout=20) # 查询操作 search = Search(using=es, index="account_info") response = search.query("match", firstname="John").execute() for hit in response: print(hit.firstname, hit.lastname) # 更新文档 doc = search.get(id="1") doc.balance += 100 doc.save() # 删除文档 search.delete(id="2") # 关闭连接 es.close() ``` 以上示例代码展示了elasticsearch_dsl的基本用法。首先我们连接到elasticsearch实例,然后可以执行查询、更新和删除操作。在查询操作中,我们使用`Search`对象来构建查询条件,并执行`execute()`方法获取查询结果。在更新操作中,我们通过获取文档对象并修改其属性值,然后调用`save()`方法保存修改。在删除操作中,我们使用`delete()`方法指定要删除的文档id。最后,我们关闭连接。 请注意,以上示例中的索引名为"account_info",如果你使用的是不同的索引,请将其替换为你的索引名。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [python中elasticsearch_dsl模块用法详解](https://blog.csdn.net/m0_72557783/article/details/126957624)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值