侧边栏壁纸
博主头像
孔子说JAVA博主等级

成功只是一只沦落在鸡窝里的鹰,成功永远属于自信且有毅力的人!

  • 累计撰写 352 篇文章
  • 累计创建 135 个标签
  • 累计收到 10 条评论

目 录CONTENT

文章目录

ES教程6-Query查询语法及示例

孔子说JAVA
2022-10-11 / 0 评论 / 0 点赞 / 293 阅读 / 9,193 字 / 正在检测是否收录...
广告 广告

es中的查询请求有两种方式,一种是简易版的查询,另外一种是使用JSON完整的请求体,叫做结构化查询(DSL)。由于DSL查询更为直观也更为简易,所以大都使用这种方式。DSL查询是POST一个json,由于post的请求是json格式的,所以存在很多灵活性,也有很多形式。本文主要讲解Query查询语法及示例。

注意官方文档里面给的例子的json结构只是一部分,并不是可以直接黏贴复制进去使用的。一般要在外面加个query为key的结构。

1、数据准备

1.1 创建索引

创建地址如下,其中 product 表示索引名称,请求方式选择PUT。

http://172.19.82.206:9200/product/

然后在请求体(Body)中,写上索引的字段名称,索引的分片数和副本数,如下:

{
    "settings": {
        "index": {
            "number_of_shards": 3,
            "number_of_replicas": 2
        }
    },
    "mappings": {
        "properties": {
            "brandName": {
                "type": "text"
            },
            "categoryName": {
                "type": "text"
            },
            "description": {
                "type": "text"
            },
            "id": {
                "type": "long"
            },
            "productName": {
                "type": "text",
                "fields": {
                    "raw": {
                        "type": "keyword",
                        "ignore_above": 256
                    }
                }
            },
            "utime": {
                "type": "date_nanos",
                "index": false
            }
        }
    }
}

image-1665205904133

1.2 添加文档

注意:ES7后type都是 _doc

es数据的插入方式如下:

PUT /product/_doc/1

其中的product是索引名;_doc是类型(ES7后type都是_doc);1代表这条数据的主键;如果id不填也,ES会自动生成一条主键,不过这时就不能用PUT了,需要使用POST添加。BODY如下:

{
    "id": 10001,
    "productName": "牛肉片(花卉牌)",
    "brandName": "花卉牌",
    "categoryName": "零食",
    "utime": 1614666414
}

image-1665206163487

查询插入结果:

GET /product/_doc/1   //查询ID为1的数据

继续添加多条文档

{"id":10002, "productName": "森马秋冬小脚库", "brandName":"森马", "categoryName":"长裤", "utime":1614667414}

{"id":10003, "productName": "加绒加厚打底衫", "brandName":"森马", "categoryName":"长衣", "utime":1614668414}

{"id":10004, "productName": "糖葫芦", "brandName":"老北京", "categoryName":"零食", "utime":1614669414}

{"id":10005, "productName": "年糕", "brandName":"老北京", "categoryName":"零食", "utime":1614667414}

2、查询分类

查询 请求方式 url格式 示例
查询某个索引信息 GET 请求 ip:port/<索引名> localhost:9200/product
指定id查询单条数据 GET 请求 ip:port/<索引名>/<类型名称>/<文档id> localhost:9200/product/_doc/1
指定索引查询数据 GET 请求 ip:port/<索引名>/_search localhost:9200/product/_search
全es查询数据 GET 请求 ip:port/_search localhost:9200/_search

ES的数据查询主要分为:

  • query查询:这种语句在执行时既要计算文档是否匹配,还要计算文档相对于其他文档的匹配度有多高。会在查询结果的每条数据中,计算一个_score 值来表示匹配度,查询结果并按_score倒序排列;

  • filter查询:在查询过程中,只判断该文档是否满足条件,不会进行匹配度计算;

所有查询操作都可以分为基础查询聚合查询符合查询

3、查询示例

查询某个索引信息、指定id查询单条数据类型均在之前的教程中有示例,请参考:

3.1 请求参数的查询(QueryString)

查询 [字段] 包含 [内容] 的文档,GET请求,基本格式:<索引名>/_search?q=<字段名>:<包含的值>,这种方式称之为 QueryString 查询方式,参数都是放在url中的,为模糊查询。

  • 注意:text与keyword搜索对比测试(keyword不会被倒排索引,不会被分词)

3.1.1 单条件查询

如查询 brandName 中包含 “北京”的商品。查询语句如下:

http://172.19.82.206:9200/product/_search/?q=brandName:北京

image-1665278059649

3.1.2 单字段多条件查询

如查询 brandName 中包含 “北京” 或 “森马”的商品。查询语句如下:

http://172.19.82.206:9200/product/_search/?q=brandName:北京 森马

image-1665278229696

3.1.3 多字段与条件查询

如查询 brandName 中包含 “北京”且 productName 中包含 “年糕”的商品。查询语句如下:

http://172.19.82.206:9200/product/_search/?q=brandName:北京&q=productName:年糕

image-1665278590503

3.2 query查询

match查询:会对查询字段进行分词操作,然后再查询(es自带分词,还可安装其他分词插件)

  • match_all:匹配所有文档

  • multi_match:指定多个字段

  • match_phrase:短语匹配查询,ElasticSearch引擎首先分析(analyze)查询字符串,从分析后的文本中构建短语查询,这意味着必须匹配短语中的所有分词,并且保证各个分词的相对位置不变

说明:假如文档字段类型是一个keyword,match 或 multi_match 就需要完全匹配才能命中,比如字段的值是234,无论是1234还是12345都不会命中,如果是match_phrase查询,只需要目标包含条件即可命中,比如目标值是 234,查询条件23|34|234可以被命中,1234或12345等不会被命中。

3.2.1 match_all 查询所有(空条件查询)

查询某个索引下的所有数据,GET/POST请求, localhost:9200/<索引名>/_search, 以下条件带不带都可以。

{
  "query": {
    "match_all": {}
  }
}
  • query: 声明查询关键词
  • match_all: 表示匹配所有

image-1665276022627

image-1665276038691

从上述2图可以看到,这个条件带与不带,查询结果都是5条数据,是一致的。

3.2.2 偏移量查询(类似于limit分页)

查询某个索引下的部分数据,POST请求, localhost:9200/<索引名>/_search

如查询前2条数据条件如下:

{
    "query": {
        "match_all": {}
    },
    "from": 0,
    "size": 2
}
  • from: 从第几条数据开始查询,第一条数据从0开始。
  • size: 数据偏移量(查询的数据量大小),类似于limit,可以单独指定size查询,默认从0开始检索。

image-1665279896355

如按照 _id 升序排序,取第 1~2 个数据:

{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "_id": {
        "order": "asc"
      }
    }
  ],
  "from": 1,
  "size": 2
}

image-1665280014274

3.2.3 对查询结果排序

对查询结果排序,POST请求, localhost:9200/<索引名>/_search

如按照 _id 降序排序获取所有数据:

{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "_id": {
        "order": "desc"
      }
    }
  ]
}

image-1665280335765

3.2.4 match 匹配字段查询

match搜索会先对搜索词进行分词,对于最基本的match搜索来说,只要搜索词的分词集合中的一个或多个存在于文档中即可,例如,当我们搜索中国杭州,搜索词会先分词为中国和杭州,只要文档中包含搜索和杭州任意一个词,都会被搜索到。

1)匹配字段查询

匹配字段查询,结果按照指定字段排序,若不期望排序去掉 sort 块即可。POST请求, localhost:9200/<索引名>/_search

{
  "query": {
    "match": {
      "brandName": "北京"
    }
  },
  "sort": [
    {
      "_id": {
        "order": "desc"
      }
    }
  ]
}
  • 指定对 brandName 字段进行相似查询
  • 查询结果按 _id 字段倒序

image-1665280568722

2)match单字段多条件or/and查询

match查询会对输入进行分词,我们可以指定对分词后的结果进行and和or查询。

  • and:代表分词后的所有结果都得匹配
  • or:代表分词后只要有一个结果匹配就行(默认是or)
-- or查询
{
    "from": 0,
    "size": 2,
    "query": {
        "match": {
            "productName": {
                "query": "森马牛肉",
                "operator": "or"
            }
        }
    }
}

-- and查询
{
    "from": 0,
    "size": 2,
    "query": {
        "match": {
            "productName": {
                "query": "森马牛肉",
                "operator": "and"
            }
        }
    }
}

3.2.5 match_phrase 短语查询

match_phrase为按短语搜索,比如根据一个文本搜索:“我的宝马多少马力”,这个文本可能会被分词成宝马、多少、马力三个短语,只有同时满足这三个才能被搜索出来。

POST请求, localhost:9200/<索引名>/_search

{
    "from": 0,
    "size": 2,
    "query": {
        "match_phrase": {
            "productName": {
                "query": "森马秋冬"
            }
        }
    }
}
  • match_phrase指定查询动作关键字

image-1665281983619

完全匹配可能比较严,我们有时候会希望有个可调节因子,少匹配一个也满足,那就需要使用到slop。

{
  "from": 0,
  "size": 2,
  "query": {
    "match_phrase": {
      "productName": {
        "query": "森马",
        "slop": "1"
      }
    }
  }
}

3.2.6 multi_match 多字段匹配查询

多字段模糊查询,和match类似都是模糊查询,但multi_match可以指定多字段进行模糊查询。POST请求, localhost:9200/<索引名>/_search

{
  "query": {
    "multi_match": {
      "query": "森马",
      "fields": [
        "brandName",
        "categoryName"
      ]
    }
  }
}
  • multi_match: 声明查询动作
  • query:查询关键字
  • fields:查询目标,以上表示查询 brandName 和 categoryName 字段都包含森马的数据

image-1665282397597

匹配评分

multi_match 会涉及到匹配评分的问题。我们希望完全匹配的文档占的评分比较高,则需要使用best_fields。

{
    "from": 0,
    "size": 2,
    "query": {
        "multi_match": {
            "query": "森马花卉牌",
            "fields": [
                "brandName",
                "categoryName"
            ],
            "type": "best_fields",
            "tie_breaker": 0.3
        }
    }
}

意思就是完全匹配"森马花卉牌"的文档评分会比较靠前,如果只匹配森马的文档评分乘以0.3的系数。

如果我们希望越多字段匹配的文档评分越高,就要使用most_fields。

{
    "from": 0,
    "size": 2,
    "query": {
        "multi_match": {
            "query": "森马花卉牌",
            "fields": [
                "brandName",
                "categoryName"
            ],
            "type": "most_fields"
        }
    }
}

如果我们会希望这个词条的分词词汇是分配到不同字段中的,那么就使用cross_fields

{
    "from": 0,
    "size": 2,
    "query": {
        "multi_match": {
            "query": "森马花卉牌",
            "fields": [
                "brandName",
                "categoryName"
            ],
            "type": "cross_fields"
        }
    }
}

3.2.7 query_string查询

query_string和match类似,但是match需要指定字段名,query_string是在所有字段中搜索,范围更广泛(当然query_string也支持指定字段查询)。POST请求, localhost:9200/<索引名>/_search

{
    "from": 0,
    "size": 20,
    "query": {
        "query_string": {
            "query": "森马"
        }
    }
}

image-1665361020033

{
  "from": 0,
  "size": 20,
  "query": {
    "query_string": {
      "query": "森马",
      "fields": [
        "productName",
        "categoryName"
      ]
    }
  }
}

image-1665361074577

query_string查询其他示例:

{
    "query": {
        "query_string": { -- 声明查询动作
            "query": "英语 AND 上册"  -- 查询即包含英语也包含上册的数据。
        }
    }
}

同时还支持或运算符和括号运算符,如下:

{
    "query": {
        "query_string": {
            "query": "(英语 AND 上册) OR 张三"  -- 表示查询包含(英语和上册)关键字或者张三关键字的数据
        }
    }
}

指定具体字段

{
    "query": {
        "query_string": {
            "query": "(英语 AND 上册) OR 张三",
            "fields": [ -- 指定从title字段中查询
                "title"
            ]
        }
    }
}

3.2.8 exists 判断字段是否存在

exists 用来判断指定字段是否存在。POST请求, localhost:9200/<索引名>/_search

{
  "query": {
    "exists": {
      "fiels": "brandName"
    }
  }
}

image-1665280798846

如将上面的 brandName 改为 brandName1,则查询结果显示 hits 的值为0,表示该字段不存在。

image-1665280776906

3.2.9 _source 返回指定属性

_source 用来指定查询结果返回的属性名称。POST请求, localhost:9200/<索引名>/_search

如查询结果中只返回 _idbrandName 属性:

{
  "query": {
    "match": {
      "brandName": "北京"
    }
  },
  "_source": [
    "_id",
    "brandName"
  ]
}

3.2.10 term 精确查询

精确查询,不会对输入做分词,如果输入的是"某某人",则直接查询"某某人",如果输入的是"某某事",则直接查询"某某事"。

{
  "query": {
    "term": {
      "id": 10002
    }
  }
}

image-1665281476406

注意:text类型term查询不到

  • ① 我想要进行查询的字段在创建mapping时使用的“text”数据类型进行创建。
  • ② 众所周知text类型的数据在elasticsearch中会进行分词并建立倒排索引,因此它会对每个词进行索引,而不会建立整个句子的索引。
  • ③ term搜索时会对整个句子作为关键词进行搜索,由于没有建立整个句子的关键词索引,因此无法查找到东西。

3.2.11 terms多个值匹配

terms 可以给一个字段指定多个值进行匹配。

{
  "query": {
    "terms": {
      "id": [
        10002,
        10003
      ]
    }
  }
}

image-1665374906415

3.2.12 前缀查询

{
  "query": {
    "match_phrase_prefix": {
      "brandName": {
        "query": "森",
        "slop": 1
      }
    }
  }
}

image-1665375270351

3.2.13 正则表达式查询

Elasticsearch 也支持正则表达式查询,通过 regexp query 可以查询指定字段包含与指定正则表达式匹配的文档。可以代表任意字符, “a.c.e” 和 “ab…” 都可以匹配 “abcde”,a{3}b{3}、a{2,3}b{2,4}、a{2,}{2,} 都可以匹配字符串 “aaabbb”。

例如需要匹配以 W 开头紧跟着数字的邮政编码,使用正则表达式查询构造查询语句如下:

{
  "query": {
    "regexp": {
      "postcode": "W[0-9].+"
    }
  }
}

image-1665375593669

0

评论区