Skip to content

Query DSL

Query DSL (Query Domain Specified Language 特殊领域查询语言),利用 REST API 传递 JSON 格式的请求数据与 ES 进行交互查询。这种方式的丰富查询方法让 ES 检索更强大、简洁。

Syntax

GET /<INDEX_NAME>/_doc/_search
{
    <DSL>
}


GET /<INDEX_NAME>/_search
{
    <DSL>
}

Example

1
2
3
4
5
6
7
8
GET {{host}}/product/_search HTTP/1.1
Content-Type: application/json

{
    "query": {
        "match_all": {}
    }
}
HTTP/1.1 200 OK
content-type: application/json; charset=UTF-8
content-encoding: gzip
content-length: 313

{
    "took": 1,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 3,
            "relation": "eq"
        },
        "max_score": 1.0,
        "hits": [
            {
                "_index": "product",
                "_type": "_doc",
                "_id": "3",
                "_score": 1.0,
                "_source": {
                    "title": "IPhone 11",
                    "price": 7999.99,
                    "description": "balabala11",
                    "create_at": "2022-07-19"
                }
            },
            {
                "_index": "product",
                "_type": "_doc",
                "_id": "1",
                "_score": 1.0,
                "_source": {
                    "title": "Andriod1",
                    "price": 1999.00,
                    "description": "Androd yyds",
                    "create_at": "2022-06-06"
                }
            },
            {
                "_index": "product",
                "_type": "_doc",
                "_id": "2",
                "_score": 1.0,
                "_source": {
                    "title": "Iphone1",
                    "price": 4999.00,
                    "description": "Iphone yyds",
                    "create_at": "2022-06-06"
                }
            }
        ]
    }
}

常见检索

基本查询

查询所有 match_all

Note

返回索引中全部文档

1
2
3
4
5
6
GET /<INDEX_NAME>/_search
{
    "query": {
        "match_all:" {}
    }
}

关键词查询 term

Note

使用关键词查询

GET /<INDEX_NAME>/_search
{
    "query": {
        "term:" {
            "<FIELD>": {
                "value": <VALUE>
            }
        }
    }
}

keyword、integer、double、date 这些都是不分词的。

text 类型默认使用 ES 标准分词器。标准分词器对中文是单字分词,对英文是单词分词。

Example
GET {{host}}/product/_search HTTP/1.1
Content-Type: application/json

{
    "query": {
        "term": {
            "price": {
                "value": 4999.00
            }
        }
    }
}
HTTP/1.1 200 OK
content-type: application/json; charset=UTF-8
content-encoding: gzip
content-length: 240

{
    "took": 2,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
        "value": 1,
        "relation": "eq"
        },
        "max_score": 1.0,
        "hits": [
            {
                "_index": "product",
                "_type": "_doc",
                "_id": "2",
                "_score": 1.0,
                "_source": {
                    "title": "Iphone1",
                    "price": 4999.00,
                    "description": "Iphone yyds",
                    "create_at": "2022-06-06"
                }
            }
        ]
    }
}

范围 range

Note

用于指定查询范围内的文档

GET /<INDEX_NAME>/_search
{
    "query": {
        "range:" {
            "<FIELD>": {
                "<OPERATOR>": <VALUE>
                "relation": "<INTERSECTS | CONTAINS | WITHIN>"
                "boost": 1.0
            }
        }
    }
}

Operator 操作符包括:

  • gt: 大于
  • gte: 大于等于
  • lt: 小于
  • lte: 小于等于
  • format: VALUE为字符串,匹配 data 用
  • time_zone: 指定时区的偏移量

relation 用于指定查询策略:

  • INTERSECTS(默认):将文档与查询的范围做交集运算然后匹配
  • CONTAINS:完全包含查询范围才算命中
  • WITHIN:在查询范围内才算命中

boost 权重:用于提升在多范围查询时,当前范围的权重,默认1.0

Example
GET {{host}}/product/_search HTTP/1.1
Content-Type: application/json

{
    "query": {
        "range": {
            "price": {
                "gt": 1000,
                "lt": 5000,
            }
        }
    }
}
HTTP/1.1 200 OK
content-type: application/json; charset=UTF-8
content-encoding: gzip
content-length: 266

{
    "took": 11,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 2,
            "relation": "eq"
        },
        "max_score": 1.0,
        "hits": [
            {
                "_index": "product",
                "_type": "_doc",
                "_id": "1",
                "_score": 1.0,
                "_source": {
                    "title": "Andriod1",
                    "price": 1999.00,
                    "description": "Androd yyds",
                    "create_at": "2022-06-06"
                }
            },
            {
                "_index": "product",
                "_type": "_doc",
                "_id": "2",
                "_score": 1.0,
                "_source": {
                    "title": "Iphone1",
                    "price": 4999.00,
                    "description": "Iphone yyds",
                    "create_at": "2022-06-06"
                }
            }
        ]
    }
}

前缀 prefix

Note

使用前缀进行匹配查询

GET /<INDEX_NAME>/_search

{
    "query": {
        "prefix": {
            "<FIELD>: {
                "value": <VALUE>
            }
        }
    }
}
GET {{host}}/product/_search HTTP/1.1
Content-Type: application/json

{
    "query": {
        "prefix": {
            "title": {
                "value": "Ip"
            }
        }
    }
}

通配符 wildcard

Note

通配符查询, 匹配一个任意字符,* 匹配多个任意字符

GET /<INDEX_NAME>/_search

{
    "query": {
        "wildcard": {
            "<FIELD>: {
                "value": <VALUE>
            }
        }
    }
}
GET {{host}}/product/_search HTTP/1.1
Content-Type: application/json

{
    "query": {
        "wildcard": {
            "title": {
                "value": "Ip*"
            }
        }
    }
}

多ID查询 ids

1
2
3
4
5
6
7
8
GET /<INDEX_NAME>/_search
{
    "query": {
        "ids": {
            "values": ["<ID>", <ID>, ...]
        }
    }
}
Example
GET {{host}}/product/_search HTTP/1.1
Content-Type: application/json

{
    "query": {
        "ids": {
            "values": ["1", "2", "3"]
        }
    }
}
HTTP/1.1 200 OK
content-type: application/json; charset=UTF-8
content-encoding: gzip
content-length: 290

{
    "took": 27,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 3,
            "relation": "eq"
        },
        "max_score": 1.0,
        "hits": [
            {
                "_index": "product",
                "_type": "_doc",
                "_id": "1",
                "_score": 1.0,
                "_source": {
                    "title": "Andriod1",
                    "price": 1999.00,
                    "description": "Andriod1 yyds",
                    "create_at": "2022-06-06"
                }
            },
            {
                "_index": "product",
                "_type": "_doc",
                "_id": "2",
                "_score": 1.0,
                "_source": {
                    "title": "Iphone1",
                    "price": 4999.00,
                    "description": "Iphone1 yyds",
                    "create_at": "2022-06-07"
                }
            },
            {
                "_index": "product",
                "_type": "_doc",
                "_id": "3",
                "_score": 1.0,
                "_source": {
                    "title": "Andriod2",
                    "price": 2999.00,
                    "description": "Andriod2 yyds",
                    "create_at": "2022-06-08"
                }
            }
        ]
    }
}

模糊查询 fuzzy

Note

用来模糊查询包含有关键词的文档

1
2
3
4
5
6
7
8
GET /<INDEX_NAME>/_search
{
    "query": {
        "fuzzy": {
            "<FIELD>": "<VALUE>"
        }
    }
}

Warning

fuzzy 模糊查询,最大模糊错误必须在 0-2 之间

  • 搜索关键词长度为 2 不允许存在模糊错误
  • 搜索关键词长度为 3-5 允许一次模糊错误
  • 搜索关键词长度大于 5 允许最大2次模糊错误
关键词长度为6(> 5)允许最大2次模糊错误
GET {{host}}/product/_search HTTP/1.1
Content-Type: application/json

{
    "query": {
        "fuzzy": {
            "description": "Iphonew"    // 错误了一个字符 w
        }
    }
}
HTTP/1.1 200 OK
content-type: application/json; charset=UTF-8
content-encoding: gzip
content-length: 302

{
    "took": 14,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 3,
            "relation": "eq"
        },
        "max_score": 0.9241961,
        "hits": [
            {
                "_index": "product",
                "_type": "_doc",
                "_id": "2",
                "_score": 0.9241961,
                "_source": {
                    "id": 2,
                    "title": "Iphone1",
                    "price": 4999.00,
                    "description": "Iphone1 yyds",
                    "create_at": "2022-06-07"
                }
            },
            {
                "_index": "product",
                "_type": "_doc",
                "_id": "4",
                "_score": 0.9241961,
                "_source": {
                    "id": 4,
                    "title": "Iphone2",
                    "price": 3999.00,
                    "description": "Iphone2 yyds",
                    "create_at": "2022-06-09"
                }
            },
            {
                "_index": "product",
                "_type": "_doc",
                "_id": "5",
                "_score": 0.9241961,
                "_source": {
                    "id": 5,
                    "title": "Iphone3",
                    "price": 6978.00,
                    "description": "Iphone3 yyds",
                    "create_at": "2022-06-10"
                }
            }
        ]
    }
}

复杂查询

布尔查询 bool

Note

bool 关键字用来组合多个条件实现复杂查询

  • must: 相当于 &&
  • should: 相当于 ||
  • must_not: 相当于 !
GET /<INDEX_NAME>/_search
{
    "query": {
        "bool": {
            "< must | should | must_not >": [
                { 
                    "<term | range | fuzzy | ...>": {
                        "<FIELD>": <VALUE>
                    }
                },
                ...other condition
            ]
        }
    }
}
Example
GET {{host}}/product/_search HTTP/1.1
Content-Type: application/json

{
    "query": {
        "bool": {
            "must": [
                {
                    "range": {
                        "price": {
                            "gt": 4999,
                            "lt": 10000
                        }
                    }
                }, {
                    "prefix": {
                        "title": {
                            "value": "Iph"
                        }
                    }
                }
            ]
        }
    }
}
HTTP/1.1 200 OK
content-type: application/json; charset=UTF-8
content-encoding: gzip
content-length: 246

{
    "took": 15,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 1,
            "relation": "eq"
        },
        "max_score": 2.0,
        "hits": [
            {
                "_index": "product",
                "_type": "_doc",
                "_id": "5",
                "_score": 2.0,
                "_source": {
                    "id": 5,
                    "title": "Iphone3",
                    "price": 6978.00,
                    "description": "Iphone3 yyds",
                    "create_at": "2022-06-10"
                }
            }
        ]
    }
}

多字段查询 multi_match

Note

multi_match 在多个字段中检索能匹配查询关键词的文档

1
2
3
4
5
6
7
8
9
GET /<INDEX_NAME>/_search
{
    "query": {
        "multi_match": {
            "query": "<QUERY_STRING>"
            "fields": ["<FIELD>", "<FIELD>", ...]
        }
    }
}

Warning

字段类型如果分词,则将查询关键词分词之后去指定的那些字段检索

字段类型如果不分词,则将查询关键词分词作为整体去指定的那些字段检索

Example

GET {{host}}/product/_search HTTP/1.1
Content-Type: application/json

{
    "query": {
        "multi_match": {
            "query": "五分钟",
            "fields": [ "title", "description" ]
        }
    }
}
虽然 title 是 keyword 类型,不分词,但是 description 是 text 类型,分词的。

ES 会将 “五分钟” 作为整体去 title 中检索,检索不到会分词成为 “五”、“分”、“钟”,然后去 description 中检索。最后检索到 id 为 4 的文档。

HTTP/1.1 200 OK
content-type: application/json; charset=UTF-8
content-encoding: gzip
content-length: 296

{
    "took": 2,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 1,
            "relation": "eq"
        },
        "max_score": 3.0841155,
        "hit
            {
                "_index": "product",
                "_type": "_doc",
                "_id": "4",
                "_score": 3.0841155,
                "_source": {
                    "id": 4,
                    "title": "Oppo",
                    "price": 3999.00,
                    "description": "充电两小时, 通话五分钟",
                    "create_at": "2022-06-09"
                }
            }
        ]
    }
}

默认字段分词查询 query_string

1
2
3
4
5
6
7
8
9
GET /<INDEX_NAME>/_search
{
    "query": {
        "query_string": {
            "default_field": "<FIELD>"
            "query": ""
        }
    }
}

过滤查询

ES 的查询操作分为两种:

  1. 匹配查询 (query)
  2. 过滤查询 (filter)

匹配查询 query 就是上面的关键词、范围、前缀、通配符、多ID、模糊查询等,这种查询是直接送达 ES 服务的。 ES 服务会计算每个返回文档的得分,然后根据得分排序。

过滤查询则会先筛选出符合的文档,并不计算得分,然后送达 ES 服务。而且过滤查询还可以缓存起来。所以从性能角度考虑,过滤比匹配更快。

Tip

过滤查询适合在大范围筛选数据,而匹配查询适合精确匹配数据。一般应用时,应先使用过滤操作过滤数据,然后使用匹配查询匹配数据。

过滤查询必须在布尔查询中。

过滤有 termtermsexistsrangeids 几种。

GET /<INDEX_NAME>/_search
{
    "query": {
        "bool": {
            "must": [ {...} ],
            "filter": [ 
                {
                    "<term | terms | exists | range | ids>": { ... }
                } 
            ]
        }
    }
}

Example

GET {{host}}/product/_search HTTP/1.1
Content-Type: application/json

{
    "query": {
        "bool": {
            "must": [{"fuzzy": {"description": {"value": "yyds"}}}],
            "filter": [{"range": {
                            "create_at": {
                                "gt": "2022-06-06",
                                "lt": "2022-06-08"
                            }
                        }}]
        }
    }
}
HTTP/1.1 200 OK
content-type: application/json; charset=UTF-8
content-encoding: gzip
content-length: 252

{
    "took": 2,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 1,
            "relation": "eq"
        },
        "max_score": 1.0700173,
        "hits": [
            {
                "_index": "product",
                "_type": "_doc",
                "_id": "2",
                "_score": 1.0700173,
                "_source": {
                    "id": 2,
                    "title": "Iphone",
                    "price": 4999.00,
                    "description": "Iphone just yyds",
                    "create_at": "2022-06-07"
                }
            }
        ]
    }
}

其他特性

高亮查询 highlight

Warning

ES7 中只有能分词的才能高亮

GET /<INDEX_NAME>/_search
{
    "query:" { ... },
    "highlight": {
        "fields": {
            "<FIELD | *>": {},
            "pre_tags": ["<PRE_TAGS>"],
            "post_tags": ["<POST_TAGS>"],
            "requiree_field_match": "<true | false>"    // 其他字段也一起高亮,false开启,true 只高亮对应字段
        }
    }
}
Example
GET {{host}}/product/_search HTTP/1.1
Content-Type: application/json

{
    "query": {
        "fuzzy": {
            "description": "Iphonew"
        }
    },
     "highlight": {
        "fields": {
            "*": {}
        }
    }
}
HTTP/1.1 200 OK
content-type: application/json; charset=UTF-8
content-encoding: gzip
content-length: 278

{
    "took": 18,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 1,
            "relation": "eq"
        },
        "max_score": 1.129573,
        "hits": [
            {
                "_index": "product",
                "_type": "_doc",
                "_id": "2",
                "_score": 1.129573,
                "_source": {
                    "id": 2,
                    "title": "Iphone",
                    "price": 4999.00,
                    "description": "Iphone just yyds",
                    "create_at": "2022-06-07"
                },
                "highlight": {  // 多出这一段即为高亮检索词的结果
                    "description": [
                        "<em>Iphone</em> just yyds"
                    ]
                }
            }
        ]
    }
}
Example
GET {{host}}/product/_search HTTP/1.1
Content-Type: application/json

{
    "query": {
        "fuzzy": {
            "description": "Iphone"
        }
    },
    "highlight": {
        "fields": { "*": {} },
        "pre_tags": ["<span style='color:red;'>"],
        "post_tags": ["</span>"]
    }
}
HTTP/1.1 200 OK
content-type: application/json; charset=UTF-8
content-encoding: gzip
content-length: 278

{
    "took": 18,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 1,
            "relation": "eq"
        },
        "max_score": 1.129573,
        "hits": [
            {
                "_index": "product",
                "_type": "_doc",
                "_id": "2",
                "_score": 1.129573,
                "_source": {
                    "id": 2,
                    "title": "Iphone",
                    "price": 4999.00,
                    "description": "Iphone just yyds",
                    "create_at": "2022-06-07"
                },
                "highlight": {  // 多出这一段即为高亮检索词的结果
                    "description": [
                        "<span style='color:red;'>Iphone</span> just yyds"
                    ]
                }
            }
        ]
    }
}

分页 from, size

Note

from 用来指定起始返回位置,默认0;size 用来指定返回条数,默认10。

size 可以单独使用,两者结合可以实现分页效果。

1
2
3
4
5
6
GET /<INDEX_NAME>/_search
{
    "query": { ... },
    "size": <SIZE>,
    "from": <FROM>
}
Example
GET {{host}}/product/_search HTTP/1.1
Content-Type: application/json

{
    "query": {
        "match_all": {}
    },
    "from": 2,
    "size": 10
}
HTTP/1.1 200 OK
content-type: application/json; charset=UTF-8
content-encoding: gzip
content-length: 381

{
    "took": 1,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 5,
            "relation": "eq"
        },
        "max_score": 1.0,
        "hits": [
            {
                "_index": "product",
                "_type": "_doc",
                "_id": "3",
                "_score": 1.0,
                "_source": {
                    "id": 3,
                    "title": "Xiaomi",
                    "price": 2999.00,
                    "description": "Xiaomi 为发烧而生",
                    "create_at": "2022-06-08"
                }
            },
            {
                "_index": "product",
                "_type": "_doc",
                "_id": "4",
                "_score": 1.0,
                "_source": {
                    "id": 4,
                    "title": "Oppo",
                    "price": 3999.00,
                    "description": "充电两小时, 通话五分钟",
                    "create_at": "2022-06-09"
                }
            },
            {
                "_index": "product",
                "_type": "_doc",
                "_id": "5",
                "_score": 1.0,
                "_source": {
                    "id": 5,
                    "title": "Vivo",
                    "price": 6978.00,
                    "description": "拍出你的美",
                    "create_at": "2022-06-10"
                }
            }
        ]
    }
}

排序 sort

默认降序 desc

GET /<INDEX_NAME>/_search
{
    "query": { ... },
    "sort": [
        { "<FIELD>": "<desc | asc>" },
        { 
            "<FIELD>": {
                "order": "<desc | asc>",
                "format": "strict_date_optional_time_nanos"
            }
        },
        { 
            "<FIELD>": {
                "order": "<desc | asc>",
                "mode": "<min | max | sum | avg | median>"
            }
        }
    ]
}

返回指定字段 _source

1
2
3
4
5
GET /<INDEX_NAME>/_search
{
    "query": { ... },
    "_source": ["<FIELD>", "<FIELD>", ...]
}
Example
GET {{host}}/product/_search HTTP/1.1
Content-Type: application/json

{
    "query": {
        "match_all": {}
    },
    "size": 2,
    "_source": ["id", "title"]
}
HTTP/1.1 200 OK
content-type: application/json; charset=UTF-8
content-encoding: gzip
content-length: 213

{
    "took": 4,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 5,
            "relation": "eq"
        },
        "max_score": 1.0,
        "hits": [
            {
                "_index": "product",
                "_type": "_doc",
                "_id": "1",
                "_score": 1.0,
                "_source": {    // 只返回指定字段
                    "id": 1,
                    "title": "Andriod"
                }
            },
            {
                "_index": "product",
                "_type": "_doc",
                "_id": "2",
                "_score": 1.0,
                "_source": {    // 只返回指定字段
                    "id": 2,
                    "title": "Iphone"
                }
            }
        ]
    }
}

去重

1
2
3
4
5
6
7
8
9
GET /<INDEX_NAME>/_search
{
    "query": {
        ...
    }
    "collapse": {
        "field": "<FIELD>"
    }
}