高级操作(Query DSL)
数据模拟
http
# 创建index & mapping
PUT /product
{
"mappings": {
"properties": {
"title": {
"type": "text"
},
"time": {
"type": "date",
"format": "yyyyMMdd"
},
"name": {
"type": "text",
"analyzer": "ik_max_word"
},
"category": {
"type": "keyword"
},
"price": {
"type": "double"
}
}
}
}
# 批量插入数据
POST /product/_bulk
{"create": {"_id": "1001"}}
{"title": "buy apple Phone", "time": 20220910, "name":"苹果手机", "category": "Phone", "price": 4999.00}
{"create": {"_id": "1002"}}
{"title": "buy huawei Phone","time": 20221120, "name":"华为手机", "category": "Phone", "price": 6999.00}
在使用默认的standard分词器时,
buy apple Phone
会被分词为buy
、apple
、phone
,注意Phone -> phone
。同样buy huawei Phone
也被分词为了buy
、huawei
、phone
。
基础查询
搜索条件包含:query(包含过滤、查询条件)、_source(自定义返回字段)、from&size(分页查询)、sort(排序,默认按照score排序)四大模块。
http
# 查询全部数据
POST /product/_search
{
"query":{
"match_all": {} // 匹配全部
},
"_source": "title", // 只返回source
"sort": [
{
"_id": { // _id倒序
"order": "desc"
}
}
]
}
# 查询全部数据进阶版
POST /{index}/_search
{
"query":{
"match_all": {} // 匹配全部
},
"_source": {"includes": ["title"], "excludes": ["_i*"]}, // 支持*,只返回includes中的排除了excludes中的字段。
"sort": [ // 多个排序条件
{"_id": "desc"},
"_score" // 默认asc顺序
]
}
匹配查询
match
http
# 单个单词查询
POST /product/_search
{
"query": {
"match": {
"title": "buy" // 通过字段匹配
}
}
}
# 多个单词查询 匹配2条(buy apple Phone 和 buy huawei Phone)
POST /{index}/_search
{
"query": {
"match": {
"title": {
"query": "apple huawei",
"operator": "or" // 多单词查询需要文档全满足或一个满足
}
}
}
}
# 高亮显示
POST /product/_search
{
"query": {
"match": {
"title": "Phone"
}
},
"highlight": {
"fields": {
"title": {
"pre_tags": "<em>",
"post_tags": "</em>"
}
}
}
}
- 在数据模拟中我们解释道,标准分词器会将大写转换为小写,所以使用
phone
去匹配时,2条数据都符合。- 如果match中查询多个单词,默认(or)是有一个符合要求的文档就会被查询出来。
match_all
http
# 完全匹配
POST /product/_search
{
"query": {
"match_all": {} // 完全匹配
}
}
multi_match
http
POST /product/_search
{
"query": {
"multi_match": {
"query": "apple",
"fields": ["title","name"]
}
}
}
等同于多个字段的match,只要有一个字段match就算匹配成功。
match_phrase
http
# 默认slop
POST /product/_search
{
"query": {
"match_phrase": {
"title": "apple phone", // buy apple Phone 和 buy huawei Phone √
"slop": 0 // 默认为0
}
}
}
# 指定slop
POST /product/_search
{
"query": {
"match_phrase": {
"title": {
"query": "buy phone", // buy apple Phone 和 buy huawei Phone √
"slop": 1
}
}
}
}
- match_phrase被称为短语搜索,要求所有的分词都必须同时出现在文档里面,且位置都必须相邻。
- slop表示短语分词后,各个词之间的距离整合后进行匹配查询,slop=1时,
buy phone
等于buy * phone
。
match_phrase_prefix
http
POST /product/_search
{
"query": {
"match_phrase_prefix": {
"title": {
"query": "buy apple",
"max_expansions": 10
}
}
}
}
match_phrase_prefix在match_phrase基础上进行查询,如果查询词为
buy apple
,那么根据buy apple *
进行匹配,默认最多返回50个匹配的结果,可以通过设置max_expansions
限制结果返回。常用于搜索时的auto complete
。
精确查询
term
http
POST /product/_search
{
"query": {
"term": { // term完全匹配
"category": "Phone"
}
}
}
- term与match不同点在于:term是精确匹配,term不会对搜索词进行分词。
- 例如category是text类型,对应的文档值是
huaiwei phone
,那么经过默认分词器会出现huawei
和phone
两个token(单词),此时用term去匹配,如果搜索词是huawei
,那么可以匹配到,如果是huawei phone
,那么无法匹配。- 若
category
是keyword
类型(添加文档字段不会被分词),那么经过默认分词器会出现一个huawei phone
的token,此时用term去匹配,如果是huawei
,那么无法匹配到,如果是huawei phone
,则是可以匹配到。
terms
http
POST /product/_search
{
"query": {
"bool": {
"must": [
{
"terms": { // 效果等同于title in ("buy", "huawei")
"title": [
"buy",
"huawei"
]
}
}
]
}
}
}
- term适用于一个词(一个体现在不分词,而不是一个单词),terms用于匹配多个词,效果等同于SQL中的in (?,?)查询。
条件查询
bool
http
# 多条件bool查询
POST /{index}/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"title": "phone"
}
}
],
"must_not": [
{
"range": {
"time": {
"gt": "now-4M/M"
}
}
}
],
"should": [
{
"term": {
"name": "手机"
}
}
]
}
}
}
- must、must_not、should分别对应Sql中的and、not和or。filter可用于范围过滤,但是并不作用于score计算。
- 每个关键字里面都可以包含多个条件,多个关键字组合使用时,必须保证三者都满足的文档才会被返回。
- (title="phone") && (time < now-4M/M) && (name="手机") = true的文档才会被返回。
过滤器
filter
http
POST /product/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"title": "phone"
}
}
],
"filter": [
{
"range": {
"time": {
"gte": 20221010,
"lte": 20230101
}
}
}
]
}
}
}
- query查询注重匹配度,filter注重是否匹配,filter适合大范围筛选数据,query适合精确匹配数据,两者可以配合使用。
- filter可以进行缓存匹配,命中就返回文档,而query需要进行额外一步(计算score)并且不支持缓存。
- ES通过bitmap(0/1)集合来表示文档是否匹配过滤器,那么在过滤器应用于其他请求时,就不需要再次计算匹配。
- filter不光可以作用在
bool
查询中,也支持在aggs
聚合中使用。
其他查询
query_string
http
POST /product/_search
{
"query": {
"query_string": { // 更推荐simple_query_string
"default_field": "nick_name",
"fields": ["nick_name", "title"], // 与default_field不能共存,只能二选一出现。
"query": "apple Phone1" // 默认会对搜索词进行分词再匹配,与match相同。
}
}
}
- query_string在不显式指定default_field属性时,默认会对所有文档的字段都进行匹配。会影响性能,不推荐使用。
- 相比query_string,更推荐simple_query_string,使用时必须要指定查询哪些字段。
range
http
# 范围查询
POST /product/_search
{
"query": {
"range": {
"time": {
"lte": "20221101"
}
}
}
}
# 范围查询,指定日期格式
POST /product/_search
{
"query": {
"range": {
"time": {
"lte": "2022-11-01",
"format": "yyyy-MM-dd||yyyyMMdd" // ES会将输入的yyyy-MM-dd的参数转换为yyyyMMdd
}
}
}
}
- 基于时间进行查询时,需要注意输入的格式需要与mapping中定义的格式相同。
- date类型支持表达式(y表示年,M表示月,d表示天),比如
20221010||/M
表示为20221001
,20221010||/y
表示为20220101
,now-1y/d
表示为当前时间减1年后包含日的时间,若now为20221010
,那么结果为20211010
。同理now-4M/M
,结果为20220601
。
prefix
http
POST /product/_search
{
"query": {
"prefix": {
"title": {
"value": "苹果"
}
}
}
}
- prefix不会对搜索词进行分析,大小写敏感,score永远为1,不能缓存的filter。
wildcard
http
POST /product/_search
{
"query": {
"wildcard": {
"title": {
"value": "b*"
}
}
}
}
- wildcard使用通配符进行查询,*匹配多个字符或汉字,?匹配一个字符或汉字。
- 大小写敏感,如果是
buy apple phone
,那么通配符是bu*
这种才可以,buy app*
是不能完全匹配的。- 尽量避免
*b
这样的操作,和mysql一样,避免左通配让索引失效。
exist
http
POST /product/_search
{
"query": {
"bool": {
"filter": [
{
"exists": {
"field": "name"
}
}
]
}
}
}
用于判断字段是否存在,存在会返回文档信息。