https://www.knowledgedict.com/tutorial/elasticsearch-query.html
match query
match_phrase query
match_phrase_prefix query
multi_match query
query_string query
simple_query_string
term query
terms query
range query
exists query
prefix query
wildcard query
regexp query
fuzzy query
type query
0ids query
bool query
boosting query
constant_score query
dis_max query
function_score query
indices query
nested query
has_child query
has_parent query
geo_distance query
geo_bounding_box query
geo_polygon query
geo_shape query
more_like_this query
script query
percolate query
GET data_record/_search
{
"query": {
"match": {
"fieldTitle": {
"query": "力量 全国"
}
}
}
}
等同于 or 匹配操作,如下:
GET data_record/_search
{
"query": {
"match": {
"fieldTitle": {
"query": "力量 全国",
"operator": "or"
}
}
}
}
如果想查询匹配所有关键词的文档,可以用 and 操作符连接,如下:
GET data_record/_search
{
"query": {
"match": {
"fieldTitle": {
"query": "力量 全国",
"operator": "and"
}
}
}
}
例如,有以下 3 个文档,使用 match_phrase 查询"what a wonderful life",只有前两个文档会被匹配:
PUT data_record/test_tp/1
{ "desc": "what a wonderful life" }
PUT data_record/test_tp/2
{ "desc": "what a life"}
PUT data_record/test_tp/3
{ "desc": "life is what"}
GET data_record/test_tp/_search
{
"query": {
"match_phrase": {
"desc": "what life"
}
}
}
GET test_idx/test_tp/_search
{
"query": {
"match_phrase_prefix": {
"desc": "what li"
}
}
}
查询语句为"java 编程",查询域为 title 和 description,查询语句如下:
GET books/_search
{
"query": {
"multi_match": {
"query": "java 编程",
"fields": ["title", "description"]
}
}
}
multi_match 支持对要搜索的字段的名称使用通配符,示例如下:
GET books/_search
{
"query": {
"multi_match": {
"query": "java 编程",
"fields": ["title", "*_name"]
}
}
}
multi_match 支持 用指数符号指定搜索字段的权重。指定关键词出现在 title 中的权重是出现在 description 字段中的 3 倍,命令如下:
GET books/_search
{
"query": {
"multi_match": {
"query": "java 编程",
"fields": ["title^3", "description"]
}
}
}
simple_query_string 是一种适合直接暴露给用户,并且具有非常完善的查询语法的查询语句,接受 Lucene 查询语法,解析过程中发生错误不会抛出异常。例子如下:
GET books/_search
{
"query": {
"simple_query_string": {
"query": "\"fried eggs\" +(eggplant | potato) -frittata",
"analyzer": "snowball",
"fields": ["body^5", "_all"],
"default_operator": "and"
}
}
}
查询 title 字段中含有关键词"思想"的书籍,查询命令如下:
GET books/_search
{
"query": {
"term": {
"title": "思想"
}
}
}
{
"query": {
"terms": {
"title": ["java", "python"]
}
}
}
例如,想要查询价格大于 50,小于等于 70 的书籍,即 50 < price <= 70,构造查询语句如下:
GET bookes/_search
{
"query": {
"range": {
"price": {
"gt": 50,
"lte": 70
}
}
}
}
查询出版日期在 2015 年 1 月 1 日和 2019 年 12 月 31 之间的书籍,对 publish_time 字段进行范围查询,命令如下:
{
"query": {
"range": {
"publish_time": {
"gte": "2015-01-01",
"lte": "2019-12-31",
"format": "yyyy-MM-dd"
}
}
}
}
如果publish_time是字符串类型,这样查询时查不到结果的,需要在字段上加上.keyword
{
"query": {
"range": {
"publish_time.keyword": {
"gte": "2015-01-01",
"lte": "2019-12-31",
"format": "yyyy-MM-dd"
}
}
}
}
exists 查询会返回字段中至少有一个非空值的文档。
{
"query": {
"exists": {
"field": "user"
}
}
}
{ "user" : "jane" } 有 user 字段,且不为空。
{ "user" : "" } 有 user 字段,值为空字符串。
{ "user" : "-" } 有 user 字段,值不为空。
{ "user" : [ "jane" ] } 有 user 字段,值不为空。
{ "user" : [ "jane", null ] } 有 user 字段,至少一个值不为空即可。
{ "user" : null } 虽然有 user 字段,但是值为空。
{ "user" : [] } 虽然有 user 字段,但是值为空。
{ "user" : [null] } 虽然有 user 字段,但是值为空。
{ "foo" : "bar" } 没有 user 字段。
prefix 查询用于查询某个字段中以给定前缀开始的文档,比如查询 title 中含有以 java 为前缀的关键词的文档,那么含有 java、javascript、javaee 等所有以 java 开头关键词的文档都会被匹配。
查询 description 字段中包含有以 win 为前缀的关键词的文档,查询语句如下:
GET books/_search
{
"query": {
"prefix": {
"description": "win"
}
}
}
如果查询不到,可以在description 字段加上.keyword
GET books/_search
{
"query": {
"prefix.keyword": {
"description": "win"
}
}
}
下面举一个 wildcard 查询的例子,假设需要找某一作者写的书,但是忘记了作者名字的全称,只记住了前两个字,那么就可以使用通配符查询,查询语句如下:
GET books/_search
{
"query": {
"wildcard": {
"author": "李永*"
}
}
}
如果查询不到,可以在 author 字段加上.keyword
GET books/_search
{
"query": {
"wildcard": {
"author.keyword": "李永*"
}
}
}
例如需要匹配以 W 开头紧跟着数字的邮政编码,使用正则表达式查询构造查询语句如下:
GET books/_search
{
"query": {
"regexp": {
"postcode": "W[0-9].+"
}
}
}
如果查询不到,可以在 postcode 字段加上.keyword
GET books/_search
{
"query": {
"regexp": {
"postcode.keyword": "W[0-9].+"
}
}
}
举例如下,用户在输入查询关键词时不小心把 “javascript” 拼成 “javascritp”,在存在拼写错误的情况下使用模糊查询仍然可以搜索到含有 “javascript” 的文档,查询语句如下:
GET books/_search
{
"query": {
"fuzzy": {
"title": "javascript"
}
}
}
type query 用于查询具有指定类型的文档。例如查询 Elasticsearch 中 type 为 computer 的文档,查询语句如下:
GET books/_search
{
"query": {
"type": {
"value": "computer"
}
}
}
例如,查询类型为 computer,id 为 1、3、5 的文档,本质上是对文档 _id 的查询,所以对应的 value 是字符串类型,查询语句如下:
GET books/_search
{
"query": {
"ids": {
"type": "computer",
"values": ["1", "3", "5"]
}
}
}
es 查询中如果要排除一些指定的 id 列表可以结合 ids query 和 bool 查询的 must_not
假设要查询 title 中包含关键词 java,并且 price 不能高于 70,description 可以包含也可以不包含虚拟机的书籍,构造 bool 查询语句如下
GET books/_search
{
"query": {
"bool": {
"filter": {
"term": {
"status": 1
}
},
"must_not": {
"range": {
"price": {
"gte": 70
}
}
},
"must": {
"match": {
"title": "java"
}
},
"should": [
{
"match": {
"description": "虚拟机"
}
}
],
"minimum_should_match": 1
}
}
}
如果我们想对 2015 年之前出版的书降低评分,可以构造一个 boosting 查询,查询语句如下:
GET books/_search
{
"query": {
"boosting": {
"positive": {
"match": {
"title": "python"
}
},
"negative": {
"range": {
"publish_time": {
"lte": "2015-01-01"
}
}
},
"negative_boost": 0.2
}
}
}
boosting 查询中指定了抑制因子为 0.2,publish_time 的值在 2015-01-01 之后的文档得分不变,publish_time 的值在 2015-01-01 之前的文档得分为原得分的 0.2 倍。
下面的查询语句会返回 title 字段中含有关键词 elasticsearch 的文档,所有文档的评分都是 1.8:
GET books/_search
{
"query": {
"constant_score": {
"filter": {
"term": {
"title": "elasticsearch"
}
},
"boost": 1.8
}
}
}
请看下面的例子:
GET books/_search
{
"query": {
"dis_max": {
"tie_breaker": 0.7,
"boost": 1.2,
"queries": [{
"term": {
"age": 34
}
},
{
"term": {
"age": 35
}
}
]
}
}
}
下面这条查询语句会返回 books 索引中的所有文档,文档的最大得分为 5,每个文档的得分随机生成,权重的计算模式为相乘模式。
GET books/_search
{
"query": {
"function_score": {
"query": {
"match all": {}
},
"boost": "5",
"random_score": {},
"boost_mode": "multiply"
}
}
}
使用脚本自定义评分公式,这里把 price 值的十分之一开方作为每个文档的得分,查询语句如下:
GET books/_search
{
"query": {
"function_score": {
"query": {
"match": {
"title": "java"
}
},
"script_score": {
"inline": "Math.sqrt(doc['price'].value/10)"
}
}
}
}
下面的查询语句实现了搜索索引 books、books2 中 title 字段包含关键字 javascript,其他索引中 title 字段包含 basketball 的文档,查询语句如下:
GET books/_search
{
"query": {
"indices": {
"indices": ["books", "books2"],
"query": {
"match": {
"title": "javascript"
}
},
"no_match_query": {
"term": {
"title": "basketball"
}
}
}
}
}
在 Elasticsearch 这样的分布式系统中执行全 SQL 风格的连接查询代价昂贵,是不可行的。相应地,为了实现水平规模地扩展,Elasticsearch 提供了以下两种形式的 join:
文档中可能包含嵌套类型的字段,这些字段用来索引一些数组对象,每个对象都可以作为一条独立的文档被查询出来(用嵌套查询)。
PUT /my_index
{
"mappings": {
"type1": {
"properties": {
"obj1": {
"type": "nested"
}
}
}
}
}
这里以员工(employee)和工作城市(branch)为例,它们属于不同的类型,相当于数据库中的两张表,如果想把员工和他们工作的城市关联起来,需要告诉 Elasticsearch 文档之间的父子关系,这里 employee 是 child type,branch 是 parent type,在映射中声明,执行命令:
PUT /company
{
"mappings": {
"branch": {},
"employee": {
"parent": { "type": "branch" }
}
}
}
使用 bulk api 索引 branch 类型下的文档,命令如下:
POST company/branch/_bulk
{ "index": { "_id": "london" }}
{ "name": "London Westminster","city": "London","country": "UK" }
{ "index": { "_id": "liverpool" }}
{ "name": "Liverpool Central","city": "Liverpool","country": "UK" }
{ "index": { "_id": "paris" }}
{ "name": "Champs Elysees","city": "Paris","country": "France" }
添加员工数据:
POST company/employee/_bulk
{ "index": { "_id": 1,"parent":"london" }}
{ "name": "Alice Smith","dob": "1970-10-24","hobby": "hiking" }
{ "index": { "_id": 2,"parent":"london" }}
{ "name": "Mark Tomas","dob": "1982-05-16","hobby": "diving" }
{ "index": { "_id": 3,"parent":"liverpool" }}
{ "name": "Barry Smith","dob": "1979-04-01","hobby": "hiking" }
{ "index": { "_id": 4,"parent":"paris" }}
{ "name": "Adrien Grand","dob": "1987-05-11","hobby": "horses" }
通过子文档查询父文档要使用 has_child 查询。例如,搜索 1980 年以后出生的员工所在的分支机构,employee 中 1980 年以后出生的有 Mark Thomas 和 Adrien Grand,他们分别在 london 和 paris,执行以下查询命令进行验证:
GET company/branch/_search
{
"query": {
"has_child": {
"type": "employee",
"query": {
"range": { "dob": { "gte": "1980-01-01" } }
}
}
}
}
搜索哪些机构中有名为 “Alice Smith” 的员工,因为使用 match 查询,会解析为 “Alice” 和 “Smith”,所以 Alice Smith 和 Barry Smith 所在的机构会被匹配,执行以下查询命令进行验证:
GET company/branch/_search
{
"query": {
"has_child": {
"type": "employee",
"score_mode": "max",
"query": {
"match": { "name": "Alice Smith" }
}
}
}
}
可以使用 min_children 指定子文档的最小个数。例如,搜索最少含有两个 employee 的机构,查询命令如下:
GET company/branch/_search?pretty
{
"query": {
"has_child": {
"type": "employee",
"min_children": 2,
"query": {
"match_all": {}
}
}
}
}
通过父文档查询子文档使用 has_parent 查询。比如,搜索工作在 UK的所有employee ,查询命令如下:
GET company/employee/_search
{
"query": {
"has_parent": {
"parent_type": "branch",
"query": {
"match": { "country": "UK }
}
}
}
}
这里准备一些城市的地理坐标作为测试数据,每一条文档都包含城市名称和地理坐标这两个字段。
首先把下面的内容保存到 geo.json 文件中:
{"index":{ "_index":"geo","_type":"city","_id":"1" }}
{"name":"北京","location":"39.9088145109,116.3973999023"}
{"index":{ "_index":"geo","_type":"city","_id": "2" }}
{"name":"乌鲁木齐","location":"43.8266300000,87.6168800000"}
{"index":{ "_index":"geo","_type":"city","_id":"3" }}
{"name":"西安","location":"34.3412700000,108.9398400000"}
{"index":{ "_index":"geo","_type":"city","_id":"4" }}
{"name":"郑州","location":"34.7447157466,113.6587142944"}
{"index":{ "_index":"geo","_type":"city","_id":"5" }}
{"name":"杭州","location":"30.2294080260,120.1492309570"}
{"index":{ "_index":"geo","_type":"city","_id":"6" }}
{"name":"济南","location":"36.6518400000,117.1200900000"}
创建一个索引并设置映射:
PUT geo
{
"mappings": {
"city": {
"properties": {
"name": {
"type": "keyword"
},
"location": {
"type": "geo_point"
}
}
}
}
}
然后执行批量导入命令:
curl -XPOST "http://localhost:9200/_bulk?pretty" --data-binary @geo.json
查找距离天津 200km 以内的城市,搜索结果中会返回北京,命令如下:
GET geo/_search
{
"query": {
"bool": {
"must": {
"match_all": {}
},
"filter": {
"geo_distance": {
"distance": "200km",
"location": {
"lat": 39.0851000000,
"lon": 117.1993700000
}
}
}
}
}
}
按各城市离北京的距离排序:
GET geo/_search
{
"query": {
"match_all": {}
},
"sort": [{
"_geo_distance": {
"location": "39.9088145109,116.3973999023",
"unit": "km",
"order": "asc",
"distance_type": "plane"
}
}]
}
查询中由两个点确定一个矩形,然后在矩形区域内查询匹配的文档。
GET geo/_search
{
"query": {
"bool": {
"must": {
"match_all": {}
},
"filter": {
"geo_bounding_box": {
"location": {
"top_left": {
"lat": 38.4864400000,
"lon": 106.2324800000
},
"bottom_right": {
"lat": 28.6820200000,
"lon": 115.8579400000
}
}
}
}
}
}
}
呼和浩特、重庆、上海三地组成一个三角形,查询位置在该三角形区域内的城市,命令如下:
GET geo/_search
{
"query": {
"bool": {
"must": {
"match_all": {}
}
},
"filter": {
"geo_polygon": {
"location": {
"points": [{
"lat": 40.8414900000,
"lon": 111.7519900000
}, {
"lat": 29.5647100000,
"lon": 106.5507300000
}, {
"lat": 31.2303700000,
"lon": 121.4737000000
}]
}
}
}
}
}
创建一个新的索引用于测试,其中 location 字段的类型设为 geo_shape 类型。
PUT geoshape
{
"mappings": {
"city": {
"properties": {
"name": {
"type": "keyword"
},
"location": {
"type": "geo_shape"
}
}
}
}
}
关于经纬度的顺序注意
1. geo_point 类型的字段,纬度在前经度在后
2. geo_shape 类型中的点,是经度在前纬度在后
把西安和郑州连成的线写入索引:
POST geoshape/city/1
{
"name": "西安-郑州",
"location": {
"type": "linestring",
"coordinates": [
[108.9398400000, 34.3412700000],
[113.6587142944, 34.7447157466]
]
}
}
查询包含在由银川和南昌作为对角线上的点组成的矩形的地理形状,由于西安和郑州组成的直线落在该矩形区域内,因此可以被查询到。命令如下:
GET geoshape/_search
{
"query": {
"bool": {
"must": {
"match_all": {}
},
"filter": {
"geo_shape": {
"location": {
"shape": {
"type": "envelope",
"coordinates": [
[106.23248, 38.48644],
[115.85794, 28.68202]
]
},
"relation": "within"
}
}
}
}
}
}
more_like_this query 可以查询和提供文本类似的文档,通常用于近似文本的推荐等场景。查询命令如下:
GET books/_search
{
"query": {
"more_like_ this": {
"fields": ["title", "description"],
"like": "java virtual machine",
"min_term_freq": 1,
"max_query_terms": 12
}
}
}
可选的参数及取值说明如下:
Elasticsearch 支持使用脚本进行查询。例如,查询价格大于 180 的文档,命令如下:
GET books/_search
{
"query": {
"script": {
"script": {
"inline": "doc['price'].value > 180",
"lang": "painless"
}
}
}
}
例如,在 my-index 索引中有一个 laptop 类型,文档有 price 和 name 两个字段,在映射中声明一个 percolator 类型的 query,命令如下:
PUT my-index
{
"mappings": {
"laptop": {
"properties": {
"price": { "type": "long" },
"name": { "type": "text" }
},
"queries": {
"properties": {
"query": { "type": "percolator" }
}
}
}
}
}
注册一个 bool query,bool query 中包含一个 range query,要求 price 字段的取值小于等于 10000,并且 name 字段中含有关键词 macbook:
PUT /my-index/queries/1?refresh
{
"query": {
"bool": {
"must": [{
"range": { "price": { "lte": 10000 } }
}, {
"match": { "name": "macbook" }
}]
}
}
}
通过文档查询 query:
GET /my-index/_search
{
"query": {
"percolate": {
"field": "query",
"document_type": "laptop",
"document": {
"price": 9999,
"name": "macbook pro on sale"
}
}
}
}
文档符合 query 中的条件,返回结果中可以查到上文中注册的 bool query。