title: ElasticSearch(七) 搜索
tags: ElasticSearch
author: Clown95html
在前面,已经介绍了在ElasticSearch索引中处理数据的基础知识,如今是时候进行核心功能的学习了。
搜索主要有两种方式:node
URI Searchgit
Request Body Searchgithub
URL检索是经过提供请求参数纯粹使用URI来执行搜索请求。
方法: curl -XGET "http://localhost:9200/movies/doc/_search?参数
,多个参数用&分开。web
经常使用参数以下:算法
参数 | 描述 |
---|---|
q | 查询字符串(映射到query_string查询) |
df | 在查询中不指定字段是默认查询的字段,若是不指定字段,ES会查询全部字段 |
analyzer | 分析查询字符串时要使用的分析器名称 |
sort | 排序,能够升序排序和降序排序 |
timeout | 指定超时时间,默认为无超时 |
from | 返回的索引匹配结果的开始值,默认为0 |
size | 要返回的搜索条数,默认为10 |
default_operator | 要使用的默认运算符能够是AND或 OR,默认为OR |
详细参数查看官方文档 :https://www.elastic.co/guide/en/elasticsearch/reference/6.2/search-uri-request.htmlsql
下面咱们来了解下怎么使用这些参数:shell
咱们首先来了解下 q
的使用,如今咱们来查找监狱风云
的信息 :json
GET /movies/doc/_search?q=%E7%9B%91%E7%8B%B1%E9%A3%8E%E4%BA%91
E7%9B%91%E7%8B%B1%E9%A3%8E%E4%BA%91 是监狱风云的 url编码
在线转码工具 :http://tool.oschina.net/encode?type=4数组
固然咱们也能够指定字段查询,例如:
GET /movies/doc/_search?q=title:%E7%9B%91%E7%8B%B1%E9%A3%8E%E4%BA%91
响应信息:
{ "took": 14, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 3, "max_score": 5.9509215, "hits": [ { "_index": "movies", "_type": "doc", "_id": "2", "_score": 5.9509215, "_source": { "title": "监狱风云1", "director": "林岭东", "year": 1987, "genres": [ "犯罪", "剧情", "动做" ], "actors": [ "周润发", "梁家辉", "张耀扬" ] } }, { "_index": "movies", "_type": "doc", "_id": "3", "_score": 3.8119292, "_source": { "title": "监狱风云2", "director": "林岭东", "year": 1991, "genres": [ "犯罪", "剧情", "动做" ], "actors": [ "周润发", "徐锦江", "陈松勇" ] } }, { "_index": "movies", "_type": "doc", "_id": "14", "_score": 1.9059646, "_source": { "title": "澳门风云3", "director": "王晶", "year": 2016, "genres": [ "搞笑", "动做" ], "actors": [ "周润发", "刘德华", "张家辉", "张学友", "余文乐" ] } } ] } }
咱们能够看到每一个被匹配出来的索引信息都有多个_score
和一个max_score
,这就是相关性评分。
默认状况下,Elasticsearch根据结果相关性评分来对结果集进行排序,所谓的「结果相关性评分」就是文档与查询条件的匹配程度。很显然,排名第一的监狱风云1
的title
字段明确的写到监狱风云
。可是为何澳门风云3
也会出如今结果里呢?首先咱们使用的是ES的默认分词器,它会把中文内容分红单个汉字,因此只要包含监狱风云
中任意一个字的文档都会被匹配出来。又由于监狱风云1
彻底匹配了监狱风云
四个字,而澳门风云3
只匹配了风云
两个字,因此监狱风云1
的_score
比澳门风云3
的_score
高
咱们先了解下这个概念,后面咱们再详细介绍
咱们再来了解下排序sort
,咱们根据year字段升序排列,例如:
GET /movies/doc/_search?q=title:%E7%9B%91%E7%8B%B1&sort=year:asc&pretty
asc 按升序排序,desc 按降序排序
_serarch
返回的内容默认只有10个文档在hits数组中。咱们的movies
有20个左右的文档,那么咱们如何看到其余文档?
和SQL使用LIMIT关键字返回只有一页的结果同样,Elasticsearch接受from和size参数,size: 表示查询多少条文档,默认10 ,from: 从第几行开始,默认0
如今咱们想要每页显示5个数据,显示3页内容:
GET /movies/doc/_search?&size=5&from=0 GET /movies/doc/_search?&size=5&from=5 GET /movies/doc/_search?&size=5&from=10
一般,GET 请求将返回文档的所有,存储在_source
参数中。可是可能你感兴趣的字段只title
。 请求个别字段可使用_source
参数。多个字段可使用逗号分隔:
GET /movies/doc/1?_source=title,actors
Url Search 支持的操做符有:
+
-
分别对应must和must not注意:
+
-
等符号url不能直接识别,要使用url encode后的结果才能够。
如今咱们来使用AND查询分类即剧情
,又是同性
GET movies/movie/_search?q=genres:(%e5%89%a7%e6%83%85 AND %e5%90%8c%e6%80%a7)&pretty
或者使用&& ,在下面的命令中咱们把 &转成了%26
GET movies/movie/_search?q=genres:(%e5%89%a7%e6%83%85 %26%26 %e5%90%8c%e6%80%a7)&pretty
咱们再来使用 +
,来进行多个匹配,只要任意知足一个便可匹配到
GET movies/movie/_search?q=genres:(%e5%89%a7%e6%83%85 %2B %e5%90%8c%e6%80%a7)&pretty
咱们还能够指定查找的范围,例如咱们查找大于1995年的信息:
curl -XGET "http://localhost:9200/movies/doc/_search?q=year:(>1995)"
查找大于1990且<2000年的信息:
GET /movies/doc/_search?q=year:(>1990 AND <2000)
前面咱们使用的Url search ,咱们也可使用请求正文来搜索信息,咱们须要向请求正文中提供查询,这种方法是咱们最经常使用的搜索方式。
为了使用ElasticSearch进行搜索,咱们使用_search
端点,可选择使用索引和类型。也就是说,按照如下模式向URL发出请求:
http://localhost:9200/<index>/<type>/_search
。其中,index和type都是可选的。
请求正文是一个JSON对象,除了其它属性之外,它还要包含一个名称为“query”的属性。这种查询方法叫查询DSL
。你可能想知道查询DSL是什么。它是ElasticSearch本身基于JSON的域特定语言,能够在其中表达查询和过滤器。
{ "query": { Query DSL here } }
Query DSL基于JSON定义的查询语言,主要包含以下两种类型:
字段类查询 :如term, match, range等,只针对某一 个字段进行查询
字段类查询主要包括如下两类:
全文匹配
针对text类型的字段进行全文检索,会对查询语句先进行分词处理,如match,match_ phrase等query类型
单词匹配
不会对查询语句作分词处理,直接去匹配字段的倒排索引,如term, terms,range等query类型
复合查询:如bool查询等,包含一个或多个字段类查询或者复合查询语句。
query_string
相似 Url serarch
里面的参数q
。
我使用query_string
(查询字符串),如今咱们来查询风云
所对应的文档。
POST movies/doc/_search { "query": { "query_string": { "query": "风云" } } }
term 查询,能够用它处理数字(numbers)、布尔值(Booleans)、日期(dates)以及文本(text),而不是全文本字段。term是表明彻底匹配,也就是精确查询,搜索前不会再对搜索词进行分词。
下面咱们查询指定的year
字段:
GET /movies/_search { "query" : { "term": { "year": {"value": 1994 } } } }
6.X以上版本term
好像是没法直接查询字符串内容,须要在字段后面添加.keyword
,例如:
GET /movies/doc/_search { "query": { "term": { "title.keyword": { "value": "大话西游" } } } }
既然已经提到了keyword
,咱们就简单的说下,title.keyword
,是es最新版本内置创建的field,就是不分词的。因此一个title
过来的时候,会创建两次索引,一次是本身自己,是要分词的,分词后放入倒排索引;另一次是基于title.keyword,不分词,保留256个字符最多,直接一个字符串放入倒排索引中。
若是一个字段既须要分词搜索,又须要精准匹配,咱们就能够经过增长keyword
字段来支持精准匹配。
{ "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }
这样至关于有address
和address.keyword
两个字段。
term
查询对于查找单个值很是有用,但一般咱们可能想搜索多个值。若是咱们想搜索多个电影信息的文档该如何处理?
咱们不须要使用多个term
查询,咱们只要用terms
查询,它至关于sql中的 in
。
使用的方法和term
同样,如今咱们来查询电影分类是动做
和剧情
的文档:
GET movies/movie/_search { "query": { "terms": { "genres.keyword": ["剧情","动做"] } } }
能够看到咱们只是把terms查询的内容使用数组替代而已,其余基本上同样。
还记得咱们以前使用URL参数搜索监狱风云
的时候,咱们还演示了指定为title
字段进行搜索。咱们再来使用match
查询来达到这样的效果,match查询
它能够被认为是基本的属性搜索查询(就是经过特定的一个或多个属性来搜索)。
match搜索会先对搜索词进行分词,对于最基本的match搜索来讲,只要搜索词的分词集合中的一个或多个存在于文档中便可,例如,当咱们搜索监狱风云
,搜索词会先分词为监狱
和风云
,只要文档中包含监狱
和风云
任意一个词,都会被搜索到 。
GET /movies/_search { "query" : { "match" : { "title" : "监狱风云" } } }
像这样指定搜索内容为title
字段这样的设置称为fields
,可用于指定要搜索的字段列表。若是不使用fields
字段,ElasticSearch查询将默认自动生成的名为_all
的特殊字段,来基于全部文档中的各个字段匹配搜索。
咱们再使用搜索引擎的时候,确定出现过拼写错误的状况,好比说咱们搜索elasticsearch
可是我不当心拼错成了elasticsearhc
,可是搜索引擎仍然给我搜索出正确的结果。
使用term
确定是不行的,由于它是精确查找,因此咱们引出fuzzy
模糊查询。
为了方便演示,咱们须要添加几个索引信息。
PUT myname/doc/1 { "name" :"clown" } PUT myname/doc/2 { "name" :"clwon" } PUT myname/doc/3 { "name" :"colwn" }
如今咱们须要查询clown
这个文档:
GET myname/doc/_search { "query": { "fuzzy": { "name": { "value": "clown", "fuzziness": 2 } } } }
fuzziness
是你的搜索文本最多能够纠正几个字母去跟你的数据进行匹配,默认若是不设置,就是2。
wildcard(通配符)查询和prefix查询相似,也是一个基于词条的低级别查询。可是它可以让你指定一个模式(Pattern),而不是一个前缀(Prefix)。它使用标准的shell通配符:?用来匹配任意字符,*用来匹配零个或者多个字符。
咱们来演示下:
GET myname/doc/_search { "query": { "wildcard": { "name": { "value": "cl*n" } } } }
若是咱们须要指定多字段,可使用multi_match
,来指定一个fields
属性用来要搜索的字段数组。
GET /movies/_search?pretty { "query": { "multi_match" : { "query" : "监狱风云", "fields" : ["title"] } } }
咱们能够看到上面的请求正文,指定了一个查询,而且使用multi_match
进行多个匹配。而后经过query
指定查询内容,并经过fields
限制查询的字段。
字段也能够经过通配符指定:
GET /movies/_search?pretty { "query": { "multi_match" : { "query" : "监狱风云", "fields" : ["tit*"] } } }
filter 相似于 SQL 里面的where 语句,和上面的基础查询比起来,也能实现搜索的功能,同时 filter不计算相关性,而且能够将查询缓存到内存当中,所以,filter速度要快于query。tan
"filter": { Filter to apply to the query }
这时候咱们就可使用到过滤, 由于我知道监狱风云2是在1991年上映的,因此我使用year
过滤出1991年的监狱风云
POST /_search { "query": { "bool": { "must": { "query_string": { "query": "监狱风云" } }, "filter": { "term": { "year": 1991 } } } } }
在上面的示例中,使用过滤器限制查询字符串查询的结果。若是咱们想只是单纯的过滤呢?也就是说,咱们但愿全部电影符合必定的标准。
在这种状况下,咱们仍然在搜索请求正文中使用query
属性。可是,咱们不能只是添加一个过滤器,须要将它包装在某种查询中。
一个解决方案是修改当前的搜索请求,替换查询字符串 query 过滤查询中的match_all
查询,这是一个查询,匹配一切内容。
好比说我想过滤出全部电影中上映时间是1994年的电影:
POST /_search { "query": { "bool": { "must": { "match_all": { } }, "filter": { "term": { "year": 1994 } } } } }
GET /_search { "query": { "bool": { "filter": { "exists": { "field": "title" } } } } }
ElasticSearch提供了一种特殊的缓存,即过滤器缓存(filter cache),用来存储过滤器的结果,被缓存的过滤器并不须要消耗过多的内存(由于它们只存储了哪些文档能与过滤器相匹配的相关信息),并且可供后续全部与之相关的查询重复使用,从而极大地提升了查询性能。
注意:ElasticSearch并非默认缓存全部过滤器,如下过滤器默认不缓存:
numeric_range script geo_bbox geo_distance geo_distance_range geo_polygon geo_shape and or not
exists,missing,range,term,terms默认是开启缓存的
开启方式:在filter查询语句后边加上 "_catch":true
上面的查询咱们有一个更简单的方法是使用常数分数查询,该查询可以包含一个查询或者一个过滤器,全部匹配文档的相关度分值都为1,不考虑TF/IDF:
curl -H "Content-Type: application/json" -XPOST "http://localhost:9200/_search" -d' { "query": { "constant_score": { "filter": { "term": { "year": 1994 } } } } }'
范围查询主要针对数值和日期类型,range 可使用比较关键词,也可使用自带参数。
比较关键词:
参数:
咱们先来查询下数值范围
POST movies/movie/_search { "query": { "range": { "year": { "gte": 1990, "lte": 2000 } } } }
固然也可使用:
POST movies/movie/_search { "query": { "range": { "year": { "from": 1990, "to": 2000 } } } }
由于咱们以前没有含日期的索引,因此咱们如今来建立几个。
PUT students/doc/1 { "name" :"Jay", "birth" :"1995-06-07" } PUT students/doc/2 { "name" :"Arlis", "birth" :"1990-02-02" } PUT students/doc/3 { "name" :"Nike", "birth" :"1980-02-02" } PUT students/doc/4 { "name" :"Yves", "birth" :"2004-05-06" }
好了如今咱们已经有数据,开始查询:
POST students/doc/_search { "query": { "range": { "birth": { "gte": "2000-01-01" } } } }
日期提供一种更友好的计算方式
POST students/doc/_search { "query": { "range": { "birth": { "gte": "now-20y" } } } }
now
表明当前系统时间, 20y
表明20年 , now-20y
即在如今的时间基础上减小20年
日期计算的操做符主要有三个 +
-
/d
,例如:
目前咱们能够在字段中搜索单独的一个词,可是有时候你想要确切的匹配若干个单词或者短语(phrases). 咱们只须要把match
变为match_phrase
便可。
match_phrase
和match
的区别,match_phrase
首先分析查询字符串,从分析后的文本中构建短语查询,这意味着必须匹配短语中的全部分词,而且保证各个分词的相对位置不变,通俗的讲就是返回的结果,跟搜索内容的分词的顺序是同样的。
例如:
GET movies/movie/_search { "query": { "match_phrase": { "title": "罗马假日" } } }
上面咱们使用了match_phrase
搜索了 罗马假日
,可以获得索引信息。
下面咱们搜索假日罗马
GET movies/movie/_search { "query": { "match_phrase": { "title": "假日罗马" } } }
咱们发现没有获得任何结果。
咱们还可使用match_phrase_prefix
来查询前缀, 为何是match_phrase_prefix
而不是match_prefix
其实也很好理解,由于前缀是须要顺序的,必须在前面。
GET movies/movie/_search { "query": { "match_phrase_prefix": { "title": "霸王" } } }
当搜索的字段有多个时,能够对指定字段进行排序。注意的是文本内容不能进行排序。
咱们使用sort
指定字段进行排序, 可使用order
指定排序方法。
order的值能够为:
下面咱们对year
进行升序排序:
GET /movies/_search?pretty { "query": { "match_all":{ } }, "sort": [ {"year": {"order": "asc"}} ] }
对year
进行降序排序:
GET /movies/_search?pretty { "query": { "match_all":{ } }, "sort": [ {"year": {"order": "desc"}} ] }
当一个字段的内容有多个值的时候,系统支持一些计算进行排序,包括min、max、sum、avg、median (中间值)。
mode | 描述 |
---|---|
min | 选择最低值。 |
max | 选择最高值。 |
sum | 使用全部值的总和做为排序值。仅适用于基于数字的数组字段。 |
avg | 使用全部值的平均值做为排序值。仅适用于基于数字的数组字段。 |
median | 使用全部值的中位数做为排序值。仅适用于基于数字的数组字段。 |
咱们来演示下用法:
GET /movies/_search?pretty { "query": { "match_all":{ } }, "sort": [ {"year": {"order": "asc","mode":"min"}} ] }
实现分页搜索只须要指定from
和size
字段便可,例如:
GET /movies/_search?pretty { "from": 0, "size": 15, "query": { "match_all":{ } } }
注意:ES的from、size分页不是真正的分页,称之为浅分页。from+ size不能超过index.max_result_window 默认为10,000 的索引设置
咱们在前面说过from、size
分页是浅分页,并且最多只能显示10000个数据,若是一次性要查出来好比10万条数据,浅分页显然知足不了咱们的要求。此时通常会采起用scoll
滚动查询,一批一批的查,直到全部数据都查询完为止。
scoll
搜索会在第一次搜索的时候,保存一个当时的视图快照,后续的对文档的改动(索引、更新或者删除)都只会影响后面的搜索请求。scoll
采用基于_doc
(不使用_score)进行排序的方式,性能较高.
为了提现查询的效果咱们添加点数据。
wget https: raw.githubusercontent.com/elastic/elasticsearch/master/docs/src/test/resources/accounts.json curl -H "Content-Type: application/json" -XPOST "localhost:9200/bank/account/_bulk" --data-binary "@accounts.json"
为了使用 scroll,初始搜索请求应该在查询中指定scroll
参数,这能够告诉 Elasticsearch 须要保持搜索的上下文环境多久,如 scroll=1m
,1m是一分钟的意思,若是数据很大,那么建议等待时间长一点。
GET /bank/account/_search?scroll=5m { "query": { "range": { "age": { "gte": 20, "lte": 40 } } } }
使用上面的请求返回的结果中包含一个scroll_id
,这个 ID 能够被传递给 scroll API 来检索下一个批次的结果。
咱们用这个scroll_id
来查询
GET /_search/scroll { "scroll" : "1m", "scroll_id" : "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAE5FmcxbnNvb0ZKU0Fpb3BMRUFmeEJuaEEAAAAAAAABNxZnMW5zb29GSlNBaW9wTEVBZnhCbmhBAAAAAAAAAToWZzFuc29vRkpTQWlvcExFQWZ4Qm5oQQAAAAAAAAE7FmcxbnNvb0ZKU0Fpb3BMRUFmeEJuaEEAAAAAAAABOBZnMW5zb29GSlNBaW9wTEVBZnhCbmhB" }
固然这个响应消息还会返回一个scroll_id
,若是咱们须要不断的往下查找就须要不断的查询这些scroll_id
。
不少应用喜欢从每一个搜索结果中高亮(highlight)匹配到的关键字,这样用户能够知道为何这些文档和查询相匹配。在Elasticsearch中高亮片断是很是容易的,咱们只须要添加highlight
关键字。
请求信息:
GET students/doc/_search { "query" : { "match" : { "title" : "卢旺达饭店" } }, "highlight": { "fields" : { "title" : {} } } }
响应信息:
{ "took": 6, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 1, "max_score": 4.9041457, "hits": [ { "_index": "movies", "_type": "doc", "_id": "11", "_score": 4.9041457, "_source": { "title": "卢旺达饭店", "director": "特瑞·乔治", "year": 2004, "genres": [ "战争", "剧情", "历史" ], "actors": [ "唐·钱德尔", "苏菲·奥康内多", "杰昆·菲尼克斯" ] }, "highlight": { "title": [ "<em>卢</em><em>旺</em><em>达</em><em>饭</em><em>店</em>" ] } } ] } }
响应的内容与以前结果相同,可是在返回结果中会有一个新的部分叫作highlight
,这里包含了来自titile
字段中的文本,而且用<em></em>
来标识匹配到的内容。
Simple_Query_String
相似Query_String
,可是会忽略错误的查询语法,而且仅支持部分查询语法。
来看下面的例子 ,咱们使用|
查询包含罗马或者卢旺达的信息,可是符号附近有一些垃圾字符。
GET movies/movie/_search { "query": { "simple_query_string": { "query": "罗马 / | 、卢旺达", "fields": ["title"] } } }
咱们成功执行了命令。
如今咱们把simple_query_string
换成query_string
,在来试试。
GET movies/movie/_search { "query": { "query_string": { "query": "罗马 / | 、卢旺达", "fields": ["title"] } } }
咱们执行命令,发现报错
bool 查询容许咱们使用布尔逻辑将小的查询组成大的查询。
好比说咱们须要同时匹配到 title 含有 监狱
和 风云
的索引信息。
请求内容:
GET /movies/_search { "query":{ "bool": {"must":[ {"match":{"title":"监狱"}}, {"match":{"title":"风云"}} ] } } }
在上述示例中,`bool` `must` 子句指定了全部匹配文档必须知足的条件。
OR查询
相比之下,bool
should
的组合,两个match查询而且返回全部title
属性中包含 监狱
或 西游
的任意信息。
请求内容:
GET /movies/_search { "query":{ "bool": {"should":[ {"match":{"title":"监狱"}}, {"match":{"title":"西游"}} ] } } }
在上述例子中bool
should
子句指定了匹配文档只要知足其中的任何一个条件便可匹配。
咱们还可使用 `bool` 和`must_not`, 查询属性中不包含匹配内容的文档。 请求内容: ```bash GET /movies/_search { "query":{ "bool": {"must_not":[ {"match":{"title":"监狱"}}, {"match":{"title":"西游"}} ] } } } ``` 在上述例子中,`bool` `must_not`子句指定了其中的任何一个条件都不知足时便可匹配
咱们能够组合 must 、should 、must_not 进行复杂的查询。
GET /movies/_search { "query": { "bool": { "must": [ { "match": { "title": "监狱风云" } } ], "must_not": [ { "match": { "year": 1991 } } ] } } }
GET /movies/_search { "query": { "bool": { "must": [ { "match_all": {} }, { "bool": { "should": [ { "match": {"genres": "同性"} }, {"match": {"genres": "科幻"} } ]} } ] } } }
lasticsearch有一个功能叫作聚合(aggregations),它容许你在数据上生成复杂的分析统计。它很像SQL中的GROUP BY可是功能更强大。
咱们先插入一些数据:
POST /_bulk {"index":{"_index":"goods","_type":"doc","_id":1}} {"gname":"薯片","price":5.00,"classes":"零食","num":100} {"index":{"_index":"goods","_type":"doc","_id":2}} {"gname":"方便面","price":3.20,"classes":"零食","num":200} {"index":{"_index":"goods","_type":"doc","_id":3}} {"gname":"毛巾" ,"price":13.50, "classes":"日用品","num":60} {"index":{"_index":"goods","_type":"doc","_id":4}} {"gname":"面包" ,"price":4.50,"classes":"零食", "num":80} {"index":{"_index":"goods","_type":"doc","_id":5}} {"gname":"牙刷" ,"price":4.50, "classes":"日用品","num":100} {"index":{"_index":"goods","_type":"doc","_id":6}} {"gname":"可乐" ,"price":3, "classes":"零食","num":100}
如今咱们来查询刚刚到商品中价格最高的:
GET goods/doc/_search { "aggs": { "price_of_max": { "max": { "field": "price" } } } }
能够在aggregations
中获得查询的结果
{ ... "aggregations": { "maxprice": { "value": 13.5 } }
如今咱们来统计全部商品的单价和:
若是咱们想要屏蔽查询索引具体内容,可使用size
,把查询数量设为0
GET goods/doc/_search { "size" :0, "aggs": { "price_of_sum": { "sum": { "field": "price" } } } }
响应信息:
{ ... "aggregations": { "price_of_sum": { "value": 33.700000047683716 } } }
能够看到和为 33.7
下面咱们计算商品的平均价格
GET goods/doc/_search { "size":0, "aggs": { "price_of_avg": { "avg": { "field": "price" } } } }
响应信息:
{ ... "aggregations": { "price_of_cardi": { "value": 5.616666674613953 } } }
GET goods/doc/_search { "size":0, "aggs": { "price_of_cardi": { "cardinality": { "field": "price" } } } }
咱们来经过商品类别分组并统计商品数量:
GET goods/doc/_search { "size":0, "aggs": { "price_group_by": { "terms": { "field": "classes.keyword" } } } }
响应信息:
... ... { "aggregations": { "price_group_by": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ { "key": "零食", "doc_count": 4 }, { "key": "日用品", "doc_count": 2 } ] } } }
咱们能够看到零食的数量为4 ,日用品数量为2
数据列过滤容许在查询的时候不显示原始数据,或者显示部分原始字段。
GET /_search { "_source": false, "query" : { "term": {"year": {"value": 1994}} } }
好比说咱们只想显示movies
中title
和actors
信息。
GET /_search { "_source": "actors", "query" : { "term": {"year": {"value": 1994}} } }
咱们还可使用 includes
包含某字段,或者使用excludes
排除某字段。
例如:
GET /_search { "_source": { "includes": [ "title", "director" ], "excludes": [ "year" ] }, "query" : { "term": {"year": {"value": 1994}} } }
咱们曾经讲过,默认状况下,返回结果是按相关性倒序排列的。 可是什么是相关性? 相关性如何计算?
每一个文档都有相关性评分,用一个相对的浮点数字段_score
来表示 _score
的评分越高,相关性越高。查询语句会为每一个文档添加一个 _score
字段,评分的计算方式取决于不一样的查询类型。
不一样的查询语句用于不一样的目的:
可是通常意义上咱们说的全文本搜索是指计算内容与关键词的相似程度。
ElasticSearch的类似度算法被定义为 TF/IDF,即检索词频率/反向文档频率,包括一下内容:
单个查询可使用TF/IDF评分标准或其余方式,好比短语查询中检索词的距离或模糊查询里的检索词类似度。
相关性并不仅是全文本检索的专属。也适用于yes|no的子句,匹配的子句越多,相关性评分越高。
若是多条查询子句被合并为一条复合查询语句,好比 bool 查询,则每一个查询子句计算得出的评分会被合并到总的相关性评分中。
ElasticSearch提供了一个explain参数,将 explain 设为 true 就能够获得 _score
详细的信息。
GET /movies/_search?explain=true { "query": { "match": { "title": "龙猫" } } }
具体的响应消息由于文本太多,本身执行命令查询 ,咱们这里只分析几个重要信息
"_shard": "[movies][3]" "_node": "g1nsooFJSAiopLEAfxBnhA",
这里加入了该文档来自于哪一个节点哪一个分片上的信息,这对咱们是比较有帮助的,由于词频率和 文档频率是在每一个分片中计算出来的,而不是每一个索引中。
_explanation
会包含在每个入口,告诉你采用了哪一种计算方式,并让你知道计算的结果以及其余详情:
"description":"score(doc=3,freq=1.0 = termFreq=1.0)), product of:"
检索词的频率
"description":"idf, computed as log(1 + (docCount - docFreq + 0.5) / (docFreq + 0.5)) from:"
反向文档频率
"description":"docCount",
字符长度准则