基本的查询方式
1、query string search
GET /ecommerce/product/_search
GET /ecommerce/product/_search?q=name:yagao&sort=price:desc
ES的搜索提供的是 restful 风格,所以可以用 http 的方式来请求,上面第二条语句代表搜索参数q为name=yagao,按照价格 price 降序排列。
针对查询结果如下:
- took:耗费了几毫秒 timed_out:是否超时,这里是没有
_shards:数据拆成了多少个分片,所以对于搜索请求,会打到所有的primary shard(或者是它的某个replica shard也可以) hits.total:查询结果的数量,4个document
hits.max_score:score的含义,就是document对于一个search的相关度的匹配分数,越相关,就越匹配,分数也高
hits.hits:包含了匹配搜索的document的详细数据
2、query DSL
DSL:Domain Specified Language,特定领域的语言
http request body:请求体,可以用json的格式来构建查询语法,比较方便,可以构建各种复杂的语法,比query string search肯定强大多了
#查询所有数据
GET /ecommerce/product/_search
{
"query": {
"match_all": {}
}
}
#查询名字包含 heiren 的数据
GET /ecommerce/product/_search
{
"query":{
"match": {
"name": "heiren"
}
}
}
#查询数据同时按照价格排序,注意排序 sort 的参数是数组
GET /ecommerce/product/_search
{
"query": {
"match": {
"name": "yagao"
}
},
"sort": [
{
"price":{
"order": "desc"
}
}
]
}
#分页查询指定数据,且,指定需要查询的列,比较适合生产环境,读取指定列数据,降低IO
GET ecommerce/product/_search
{
"query":{"match_all":{}},
"from": 1,
"size":1,
"_source":["desc","price"]
}
3、query filter
#查询的数据满足特定的filter条件
#名称包含牙膏,且,价格大于等44的数据
GET /ecommerce/product/_search
{
"query":{
"bool":{
"must":{
"match":{
"tags":"meibai"
}
},
"filter":{
"range":{
"price":{"gte":44}
}
}
}
}
}
4、full-text search
#查询名称包含 gaolujie或者 yagao 的数据
GET /ecommerce/product/_search
{
"query":{
"match": {
"name":"gaolujie yagao"
}
},
"_source":["name"]
}
ES 中的数据,name 会被拆解进行倒排索引,排序结果如下:
词名 | 数据ID值 |
---|---|
yagao | 1,2,3,4 |
gaolujie | 1 |
zhonghua | 3 |
jiajieshi | 2 |
heiren | 4 |
同时在查询的时候,name 也会被拆解为 gaolujie 和 yagao
然后在查询的时候,就在分词表中匹配,匹配出这些词语,然后拿到对应的数据ID,返回,在返回前还会根据数据匹配度进行排序,匹配度越高分值越高,靠近前面
5、phrase search(短语搜索)
跟全文检索相对应,相反,全文检索会将输入的搜索串拆解开来,去倒排索引里面去一一匹配,只要能匹配上任意一个拆解后的单词,就可以作为结果返回
phrase search,要求输入的搜索串,必须在指定的字段文本中,完全包含一模一样的,才可以算匹配,才能作为结果返回
GET /ecommerce/product/_search
{
"query":{
"match_phrase": {
"producer": "gaolujie productr"
}
},
"_source":["name"]
}
查询结果只有一条数据,语法类似于SQL中的: like ‘%query char%’
6、highlight search(高亮搜索结果)
其实不算是一种查询方式吧,只是把对搜索的结果进行高亮处理,结果为html标签
GET /ecommerce/product/_search
{
"query":{
"match":{
"producer": "productr"
}
},
"_source":["name"],
"highlight": {
"fields" : {
"producer" : {}
}
}
}
7、聚合查询
a、简单的group by 操作,统计每一种类型牙膏数量
#按照 tags 来进行group
GET /ecommerce/product/_search
{
"size":0,
"aggs": {
"group_by_tags": {
"terms": {
"field": "tags",
"size": 10
}
}
}
}
执行后,会抛出如下错误,正常的,这个时候按照错误提示需要更改字段field的 fielddata 为true
#设置字段的fielddata为true, 注意在api 后面没有添加 索引的 type
PUT /ecommerce/_mapping
{
"properties":{
"tags":{
"fielddata":true,
"type":"text"
}
}
}
设置完上面的属性后,就可以再次运行下面的语句,得到想要的结果
GET /ecommerce/product/_search
{
"size":0,
"aggs": {
"group_by_tags": {
"terms": {
"field": "tags",
"size": 10
}
}
}
}
- size:0 就是不显示被检索的数据,否则会把所有搜索到的数据都现实出来
- aggs: 代表聚合操作
- group_by_tags:我们自己给当前聚合操作起的名字
- terms:代表用哪一种方式来进行聚合操作
- field:用哪一个字段来聚合
- size:10 聚合结果现实的个数,类似于SQL 总的 select top 10 id.count(1) fro tb group id;
扩展一下: 统计满足要求的每一个tag下牙膏数量
GET /ecommerce/product/_search
{
"size": 0,
"query": {
"match": {
"name": "yagao"
}
},
"aggs":{
"group_by_tags":{
"terms": {
"field": "tags",
"size": 10
}
}
}
}
b、先分组,然后在计算分组下的平均值
GET /ecommerce/product/_search
{
"size": 0,
"aggs":{
"group_by_avg":{
"terms": {
"field": "tags"
},
"aggs": {
"avg_price": {
"avg": {
"field": "price"
}
}
}
}
}
}
因为是先分组,后求平均值,所以在 terms 同一个分组查询中,类似于 SQL 中,group by 后面的 avg 道理,结果也如下所示
c、分组后求平均值,切按照平均值降序排列
GET /ecommerce/product/_search
{
"size": 0,
"aggs": {
"group_by_avg": {
"terms": {
"field": "tags",
"size": 10,
"order": {
"avg_price": "asc"
}
},
"aggs":{
"avg_price":{
"avg":{
"field":"price"
}
}
}
}
}
}
先分组,后求平均值,在根据平均值排序,平均值是针对分组的,所以,排序放在分组 terms 里面,排序的时候,是按照平均值排序,所以 order 后面跟的是求平均值的 _term 名字
类比SQL:先 group by 在 avg, 然后在 order by
d、先按照价格指定去间范围,然后在分组求平均值
GET /ecommerce/product/_search
{
"size": 0,
"aggs":{
"group_by_rang":{
"range": {
"field": "price",
"ranges": [
{
"from": 30,
"to": 40
},
{
"from": 41,
"to":100
}
]
},
"aggs": {
"grpy_by_tag": {
"terms": {
"field": "tags",
"size": 10
},
"aggs":{
"avg_price":{
"avg": {
"field": "price"
}
}
}
}
}
}
}
}
注意:分区间的时候,默认的 from 是包含,to 是不包含的
另:上面分组和分区间是平级的