一、前言
在前面的文章我们学习了ES的一些基本查询,同时用Java全部实现了一遍,今天我们继续深入学习一下ES的查询。
二、Term级别查询
在 Elasticsearch 中,Term 级别查询用于精确匹配字段值。与全文搜索不同,Term 级别查询不会进行分词处理,而是直接匹配字段的完整值。这使得 Term 级别查询非常适合用于精确匹配、过滤和聚合操作。
1、Term查询
Term是ES中用于精确匹配的关键字,可以理解为Mysql中的等于,例如我现在想搜索城市是“北京”的酒店就可以这么写:
GET /hotel/_search
{
"query": {
"term": {
"city": {
"value": "北京"
}
}
}
}
这段DSL翻译成Mysql就是 select * from hotel where `city` = '北京'
需要注意的是,尽量避免使用Term去查询Text类型的数据,因为Text会被分词,这会导致精准匹配变得困难,如果想搜索Text类型的数据可以使用Match(后面也会讲)
2、Terms查询
和Term类型,Terms也适用于精准匹配,但从名字上我们可以看出Terms是复数形式,意味着他可以支持多个条件(当然Term结合bool查询也能实现),例如我们现在想查询城市是青岛或者北京的酒店就可以这么写
GET /hotel/_search
{
"query": {
"terms": {
"city": [
"青岛",
"北京"
]
}
}
}
这段DSL翻译成Mysql就是 select * from hotel where `city` in ('北京','青岛')
terms默认最多支持65,536个值,如果要修改的话可以修改该参数 index.max_terms_count
3、Terms Set
terms_set 是 Elasticsearch 中的一种查询类型,用于执行基于集合的条件查询。与普通的 terms 查询不同,terms_set 查询允许你定义更复杂的条件,例如集合中元素的数量必须满足某些条件。
PUT /programmer
{
"mappings": {
"properties": {
"name":{
"type": "keyword"
},
"skill":{
"type": "keyword"
},
"required_matches":{
"type":"Integer"
}
}
}
}
我们的程序员索引有两个字段,姓名和技能,同时我们写入数据
POST /programmer/_bulk
{"index":{"_index":"programmer","_id":"1"}}
{"name":"张三","skill":["Java","C++","Python","JavaScript"],"required_matches":2}
{"index":{"_index":"programmer","_id":"2"}}
{"name":"李四","skill":"Python","required_matches":1}
{"index":{"_index":"programmer","_id":"3"}}
{"name":"王五","skill":["C++","Python"],"required_matches":2}
现在我们查询会C++、Python的程序员且至少会其中的几种的,在上述的文档里,张三我们设置的需要匹配(required_matches字段)等于2,李四=1,王五=2,此时我们的DSL如下
GET /programmer/_search
{
"query": {
"terms_set": {
"skill": {
"terms": [ "C++", "Python"],
"minimum_should_match_field":"required_matches"
}
}
}
}
结果如下
#! Elasticsearch built-in security features are not enabled. Without authentication, your cluster could be accessible to anyone. See https://www.elastic.co/guide/en/elasticsearch/reference/7.17/security-minimal-setup.html to enable security.
{
"took" : 878,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 3,
"relation" : "eq"
},
"max_score" : 0.7876643,
"hits" : [
{
"_index" : "programmer",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.7876643,
"_source" : {
"name" : "张三",
"skill" : [
"Java",
"C++",
"Python",
"JavaScript"
],
"required_matches" : 2
}
},
{
"_index" : "programmer",
"_type" : "_doc",
"_id" : "3",
"_score" : 0.7876643,
"_source" : {
"name" : "王五",
"skill" : [
"C++",
"Python"
],
"required_matches" : 2
}
},
{
"_index" : "programmer",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.17426977,
"_source" : {
"name" : "李四",
"skill" : "Python",
"required_matches" : 1
}
}
]
}
}
可以看到所有的文档都返回了,我们来分析一下为什么结果是这样的。
(1)首先我们的查询条件是跟据skill字段terms精准匹配
(2)minimum_should_match_field使用的是 required_matches字段
(3)terms的值为C++和Python,张三会 “Java”,“C++”,“Python”,“JavaScript”,同时只需要满足两个就算匹配上,很显然是符合条件的,所以张三返回
(4)李四,虽然李四只会Python但是他设置的是只要满足一个条件就算匹配上,所以李四也匹配上了。
(5)最后王五,也是同样的道理。所以这次返回了张三、李四、王五。
4、exists
exists不是用来查询文档的,而是用来查询索引的,比如我们想看那些索引包含指定的字段,例如我想查看包含“skill”字段的索引就可以用exists
GET /_search
{
"query": {
"exists": {
"field": "skill"
}
}
}
5、Range
Rang,用于范围匹配,例如我们想查询价格300~500的酒店,DSL可以这么写
GET /hotel/_search
{
"query": {
"range": {
"price": {
"gte": 300,
"lte": 500
}
}
}
}
这个DSL翻译成SQL 就是 select * from hotel where price >= 300 and price <=500
range可用的参数有
gt(greater than ):大于
gte(greater than or equal):大于等于
lt(less than):小于
lte(less than or equal):小于等于
format:格式化,用于日期类型比较
6、prefix
前缀匹配,有点类似于Mysql中的前缀模糊匹配,需要注意的是prefix 查询默认是不适用于 text 类型字段的。这是因为 text 字段在索引时会被分析器(analyzer)拆分成多个词项(tokens),而 prefix 查询则需要匹配完整的前缀。比如我们想搜索张开头程序员,DSL就可以这么写
GET /programmer/_search
{
"query": {
"prefix": {
"name": {
"value": "张"
}
}
}
}
7、IDs
IDs查询,就是根据文档的ID查询,这个没有太多东西可以说
GET /hotel/_search
{
"query": {
"ids" : {
"values" : ["001","002"]
}
}
}
8、Fuzzy
Fuzzy查询,模糊查询或者说近似匹配,例如电商的里的搜索场景
- 用户输入的查询词可能存在拼写错误,Fuzzy 查询可以帮助返回与拼写错误相似的结果。
- 例如,用户搜索 "aple" 时,Fuzzy 查询可以返回 "apple" 相关的结果。
这里先举个例子,后面再详细学习
GET /_search
{
"query": {
"fuzzy": {
"user.id": {
"value": "ki",
"fuzziness": "AUTO",
"max_expansions": 50,
"prefix_length": 0,
"transpositions": true,
"rewrite": "constant_score"
}
}
}
}
三、结束语
今天学习了一下ES中的 Term级别查询,ES中还有其他类型的搜索后面将继续,同时下一篇文章将用Java把上述的DSL全部实现一遍,希望对有所帮助。
�