23种非常有用的ElasticSearch查询例子

一、新建索引

为了展示Elasticsearch中不同查询的用法,先在Elasticsearch里面创建了book相关的documents,每本书主要涉及以下字段: title, authors, summary, publish_date(发行日期),publisher以及评论条数。

操作如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
curl -XPUT 'https://www.iteblog.com:9200/iteblog_book_index' -d '{ "settings": { "number_of_shards": 1 }}'

curl -XPOST 'https://www.iteblog.com:9200/iteblog_book_index/book/_bulk' -d '
{ "index": { "_id": 1 }}
{ "title": "Elasticsearch: The Definitive Guide", "authors": ["clinton gormley", "zachary tong"], "summary" : "A distibuted real-time search and analytics engine", "publish_date" : "2015-02-07", "num_reviews": 20, "publisher": "oreilly" }
{ "index": { "_id": 2 }}
{ "title": "Taming Text: How to Find, Organize, and Manipulate It", "authors": ["grant ingersoll", "thomas morton", "drew farris"], "summary" : "organize text using approaches such as full-text search, proper name recognition, clustering, tagging, information extraction, and summarization", "publish_date" : "2013-01-24", "num_reviews": 12, "publisher": "manning" }
{ "index": { "_id": 3 }}
{ "title": "Elasticsearch in Action", "authors": ["radu gheorge", "matthew lee hinman", "roy russo"], "summary" : "build scalable search applications using Elasticsearch without having to do complex low-level programming or understand advanced data science algorithms", "publish_date" : "2015-12-03", "num_reviews": 18, "publisher": "manning" }
{ "index": { "_id": 4 }}
{ "title": "Solr in Action", "authors": ["trey grainger", "timothy potter"], "summary" : "Comprehensive guide to implementing a scalable search engine using Apache Solr", "publish_date" : "2014-04-05", "num_reviews": 23, "publisher": "manning" }
'

通过dev tools来模拟则为:
http://cos.leiyawu.com/img/elk_index_check_1.png

1
2
3
4
5
6
7
8
9
POST /iteblog_book_index/book/_bulk
{ "index": { "_id": 1 }}
{ "title": "Elasticsearch: The Definitive Guide", "authors": ["clinton gormley", "zachary tong"], "summary" : "A distibuted real-time search and analytics engine", "publish_date" : "2015-02-07", "num_reviews": 20, "publisher": "oreilly" }
{ "index": { "_id": 2 }}
{ "title": "Taming Text: How to Find, Organize, and Manipulate It", "authors": ["grant ingersoll", "thomas morton", "drew farris"], "summary" : "organize text using approaches such as full-text search, proper name recognition, clustering, tagging, information extraction, and summarization", "publish_date" : "2013-01-24", "num_reviews": 12, "publisher": "manning" }
{ "index": { "_id": 3 }}
{ "title": "Elasticsearch in Action", "authors": ["radu gheorge", "matthew lee hinman", "roy russo"], "summary" : "build scalable search applications using Elasticsearch without having to do complex low-level programming or understand advanced data science algorithms", "publish_date" : "2015-12-03", "num_reviews": 18, "publisher": "manning" }
{ "index": { "_id": 4 }}
{ "title": "Solr in Action", "authors": ["trey grainger", "timothy potter"], "summary" : "Comprehensive guide to implementing a scalable search engine using Apache Solr", "publish_date" : "2014-04-05", "num_reviews": 23, "publisher": "manning" }

ES中的查询请求有两种方式,一种是简易版的查询,另外一种是使用JSON完整的请求体,叫做结构化查询(DSL)。
由于DSL查询更为直观也更为简易,所以大都使用这种方式。
DSL查询是POST过去一个json,由于post的请求是json格式的,所以存在很多灵活性,也有很多形式。

基本匹配查询主要形式:
(1)、使用Search Lite API,并将所有的搜索参数都通过URL传递
(2)、使用Elasticsearch DSL,其可以通过传递一个JSON请求来获取结果。Curl方式与其类似,只是提交方式不是POST,而是XGET,提交参数与DSL提交一致

二、基本匹配查询(Basic Match Query)
1、在所有的字段中搜索带有”guide”的结果:
通过dev tools:
GET /iteblog_book_index/book/_search?q=guide

通过curl方式:
curl -u elastic “http://10.104.37.115:9281/iteblog_book_index/book/_search?pretty" -d ‘
{
“query”: {
“multi_match” : {
“query” : “guide”,
“fields” : [“_all”]
}
}
}’

通过DSL:(POST json方式)

其输出和上面使用/iteblog_book_index/book/_search?q=guide的输出一样。上面的multi_match关键字通常在查询多个fields的时候作为match关键字的简写方式。fields属性指定需要查询的字段,如果我们想查询所有的字段,这时候可以使用_all关键字,正如上面的一样。

如果只是查询summary字段,则为:

title的Guide则不会显示。

2、以上两种方式都允许我们指定查询哪些字段。比如,我们想查询title中出现in Action的图书,那么我们可以这么查询:

GET /iteblog_book_index/book/_search?q=title:in%20action

然而,DSL方式提供了更加灵活的方式来构建更加复杂的查询(我们将在后面看到),甚至指定你想要的返回结果。下面的例子中,我将指定需要返回结果的数量,开始的偏移量(这在分页的情况下非常有用),需要返回document中的哪些字段以及高亮关键字:

curl -XGET ‘https://www.iteblog.com:9200/iteblog_book_index/book/_search' -d ‘
{
“query”: {
“match” : {
“title” : “in action”
}
},
“size”: 2, #返回结果的数量
“from”: 0, #开始的偏移量
“_source”: [ “title”, “summary”, “publish_date” ],
“highlight”: {
“fields” : {
“title” : {}
}
}
}’

三、Multi-field Search
正如我们之前所看到的,想在一个搜索中查询多个 document field (比如使用同一个查询关键字同时在title和summary中查询),你可以使用multi_match查询,使用如下:
curl -XGET ‘https://www.iteblog.com:9200/iteblog_book_index/book/_search' -d ‘
{
“query”: {
“multi_match” : {
“query” : “elasticsearch guide”,
“fields”: [“title”, “summary”]
}
}
}’

四、Boosting
上面使用同一个搜索请求在多个field中查询,你也许想提高某个field的查询权重。在下面的例子中,我们把summary field的权重调成3,这样就提高了其在结果中的权重,这样把_id=4的文档相关性大大提高了,如下:

curl -XGET ‘https://www.iteblog.com:9200/iteblog_book_index/book/_search' -d ‘
{
“query”: {
“multi_match” : {
“query” : “elasticsearch guide”,
“fields”: [“title”, “summary^3”]
}
},
“_source”: [“title”, “summary”, “publish_date”]
}’

需要注意的是:Boosting不仅仅意味着计算出来的分数(calculated score)直接乘以boost factor,最终的boost value会经过归一化以及其他一些内部的优化

五、Bool Query
在查询条件中使用AND/OR/NOT操作符,这就是布尔查询(Bool Query)。布尔查询可以接受一个must参数(等价于AND),一个must_not参数(等价于NOT),以及一个should参数(等价于OR)。比如,我想查询title中出现Elasticsearch或者Solr关键字的图书,图书的作者是clinton gormley,但没有radu gheorge,可以这么来查询:

curl -XGET ‘https://www.iteblog.com:9200/iteblog_book_index/book/_search' -d ‘
{
“query”: {
“bool”: {
“must”: {
“bool” : { “should”: [
{ “match”: { “title”: “Elasticsearch” }},
{ “match”: { “title”: “Solr” }} ] }
},
“must”: { “match”: { “authors”: “clinton gormely” }},
“must_not”: { “match”: {“authors”: “radu gheorge” }}
}
}
}’

六、Fuzzy Queries(模糊查询)
模糊查询可以在Match和 Multi-Match查询中使用以便解决拼写的错误,模糊度是基于Levenshtein distance计算与原单词的距离。使用如下:
curl -XGET ‘https://www.iteblog.com:9200/iteblog_book_index/book/_search' -d ‘
{
“query”: {
“multi_match” : {
“query” : “comprihensiv guide”,
“fields”: [“title”, “summary”],
“fuzziness”: “AUTO”
}
},
“_source”: [“title”, “summary”, “publish_date”],
“size”: 1
}’

需要注意:上面我们将fuzziness的值指定为AUTO,其在term的长度大于5的时候相当于指定值为2。然而80%的人拼写错误的编辑距离(edit distance)为1,所有如果你将fuzziness设置为1可能会提高你的搜索性能。

七、Wildcard Query(通配符查询)
通配符查询允许我们指定一个模式来匹配,而不需要指定完整的term。?将会匹配一个字符;将会匹配零个或者多个字符。比如我们想查找所有作者名字中以t字符开始的记录,我们可以如下使用:
curl -XGET ‘https://www.iteblog.com:9200/iteblog_book_index/book/_search' -d ‘
{
“query”: {
“wildcard” : { #wildcard是通配符意思
“authors” : “t

}
},
“_source”: [“title”, “authors”],
“highlight”: {
“fields” : {
“authors” : {}
}
}
}’

八、Regexp Query(正则表达式查询)
ElasticSearch还支持正则表达式查询,此方式提供了比通配符查询更加复杂的模式。比如我们先查找作者名字以t字符开头,中间是若干个a-z之间的字符,并且以字符y结束的记录,可以如下查询:

curl -XGET ‘https://www.iteblog.com:9200/iteblog_book_index/book/_search' -d ‘
{
“query”: {
“regexp” : {
“authors” : “t[a-z]*y”
}
},
“_source”: [“title”, “authors”],
“highlight”: {
“fields” : {
“authors” : {}
}
}
}’

九、Match Phrase Query(匹配短语查询)
匹配短语查询要求查询字符串中的trems要么都出现Document中、要么trems按照输入顺序依次出现在结果中。在默认情况下,查询输入的trems必须在搜索字符串紧挨着出现,否则将查询不到。不过我们可以指定slop参数,来控制输入的trems之间有多少个单词仍然能够搜索到,如下所示:
curl -XGET ‘https://www.iteblog.com:9200/iteblog_book_index/book/_search' -d ‘
{
“query”: {
“multi_match”: {
“query”: “search engine”,
“fields”: [
“title”,
“summary”
],
“type”: “phrase”,
“slop”: 3
}
},
“_source”: [
“title”,
“summary”,
“publish_date”
]
}’

从上面的例子可以看出,id为4的document被搜索(summary字段里面精确匹配到了search engine),并且分数比较高;而id为1的document也被搜索到了,虽然其summary中的search和engine单词并不是紧挨着的,但是我们指定了slop属性,所以被搜索到了。如果我们将”slop”: 3条件删除,那么id为1的文档将不会被搜索到,如下:

十、Simple Query String(简单查询字符串)
simple_query_string是query_string的另一种版本,其更适合为用户提供一个搜索框中,因为其使用+/|/- 分别替换AND/OR/NOT,如果用输入了错误的查询,其直接忽略这种情况而不是抛出异常。使用如下:(注意是POST)
curl POST https://www.iteblog.com:9200/iteblog_book_index/book/_search
{
“query”: {
“simple_query_string” : {
“query”: “(saerch1 algorithm1) + (grant ingersoll) | (tom morton)”,
“fields”: [“_all”, “summary^2”]
}
},
“_source”: [ “title”, “summary”, “authors” ],
“highlight”: {
“fields” : {
“summary” : {}
}
}
}

十一、Term/Terms Query
前面的例子中我们已经介绍了全文搜索(full-text search),但有时候我们对结构化搜索中能够精确匹配并返回搜索结果更感兴趣。这种情况下我们可以使用term和terms查询。在下面例子中,我们想搜索所有曼宁出版社(Manning Publications)出版的图书:

curl POST https://www.iteblog.com:9200/iteblog_book_index/book/_search -d ‘
{
“query”: {
“term” : {
“publisher”: “manning”
}
},
“_source” : [“title”,”publish_date”,”publisher”]
}’

还可以使用terms关键字来指定多个terms,如下:

{
“query”: {
“terms” : {
“publisher”: [“oreilly”, “packt”]
}
}
}

十二、Term Query - Sorted
词查询结果和其他查询结果一样可以很容易地对其进行排序,而且我们可以对输出结果按照多层进行排序:
curl POST https://www.iteblog.com:9200/iteblog_book_index/book/_search
{
“query”: {
“term” : {
“publisher”: “manning”
}
},
“_source” : [“title”,”publish_date”,”publisher”],
“sort”: [
{ “publish_date”: {“order”:”desc”}},
{ “title”: { “order”: “desc” }}
]
}

执行提示:
Fielddata is disabled on text fields by default. Set fielddata=true on [title] in order to load fielddata in memory by uninverting the inverted index

应该是5.x后对排序,聚合这些操作用单独的数据结构(fielddata)缓存到内存里了,需要单独开启

PUT /iteblog_book_index/_mapping/book
{
“properties”: {
“title”: {
“type”: “text”,
“fielddata”: true
}
}
}

再次执行:

十三、Range Query(范围查询)
另一种结构化查询就是范围查询。在下面例子中,我们搜索所有发行年份为2015的图书:
curl POST https://www.iteblog.com:9200/iteblog_book_index/book/_search
{
“query”: {
“range” : {
“publish_date”: {
“gte”: “2015-01-01”,
“lte”: “2015-12-31”
}
}
},
“_source” : [“title”,”publish_date”,”publisher”]
}

十四、Filtered Query(过滤查询)
过滤查询允许我们对查询结果进行筛选。比如:我们查询标题和摘要中包含Elasticsearch关键字的图书,但是我们想过滤出评论大于20的结果,可以如下使用:

curl POST https://www.iteblog.com:9200/iteblog_book_index/book/_search
{
“query”: {
“filtered”: {
“query” : {
“multi_match”: {
“query”: “elasticsearch”,
“fields”: [“title”,”summary”]
}
},
“filter”: {
“range” : {
“num_reviews”: {
“gte”: 20
}
}
}
}
},
“_source” : [“title”,”summary”,”publisher”, “num_reviews”]
}


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!