当前位置: 首页 > news >正文

Elasticsearch下篇

Elasticsearch下篇

文章目录

  • Elasticsearch下篇
    • 1 DSL查询
      • 1.1 快速入门
      • 1.2 叶子查询
        • 1.2.1 全文检索查询
        • 1.2.2 精确查询
      • 1.3 复合查询
      • 1.4 排序和分页
      • 1.5 高亮显示
    • 2 JavaRestClient
      • 2.1 快速入门
      • 2.2 构建查询条件
      • 2.3 排序和分页
      • 2.4 高亮显示
    • 3 数据聚合
      • 3.1 DSL聚合
      • 3.2 RestClient聚合

在上次学习中,我们已经导入了大量数据到elasticsearch中,实现了商品数据的存储。不过查询商品数据时 依然采用的是根据id查询,而非模糊搜索

所以今天,我们来研究下elasticsearch的数据搜索功能。Elasticsearch提供了基于JSON的DSL(Domain Specific Language)语句来定义查询条件,其JavaAPI就是在组织DSL条件。

因此,我们先学习DSL的查询语法,然后再基于DSL来对照学习JavaAPI,就会事半功倍。

1 DSL查询

Elasticsearch提供了DSL(Domain Specific Language)查询,就是以JSON格式来定义查询条件,类似这样:

>

DSL查询可以分为两大类:

  • 叶子查询(Leaf query clauses): 一般就是在特定的字段里查询特定值,属于简单查询,很少单独使用。
  • 复合查询(Compound query clauses): 以逻辑方式组合多个叶子查询或者更改叶子查询的行为方式。

在查询以后,还可以对查询的结果做处理,包括:

  • 排序:按照一个或多个字段值做排序
  • 分页:根据from和size做分页,类似MySQL
  • 高亮:对搜索结果中的关键字添加特殊样式,使其更加醒目
  • 聚合:对搜索结果做数据统计以形成报表

1.1 快速入门

基于DSL的查询语法如下:

在这里插入图片描述

# 查询所有
GET /items/_search
{"query": {"match_all": {}}
}

在这里插入图片描述

会发现虽然是match_all,但是响应结果中并不会包含索引库中的所有文档,而是仅有10条。这是因为处于安全考虑,elasticsearch设置了默认的查询页数。

1.2 叶子查询

叶子查询还可以进一步细分,常见的有:

  • 全文检索(full text)查询: 利用分词器对用户输入内容分词,然后去词条列表中匹配。例如:
    • match_query
    • multi_match_query
  • 精确查询: 不对用户输入内容分词,直接精确匹配,一般是查找Keyword、数值、日期、布尔等类型。例如:
    • ids
    • range
    • term
  • 地理(geo)查询: 用于搜索地理位置,搜索方式很多。例如:
    • geo_distance
    • geo_bounding_box
1.2.1 全文检索查询

match查询: 全文检索查询的一种,会对用户输入内容分词,然后去倒排索引库检索,语法:

multi_match: 与match查询类似,只不过允许同时查询多个字段,语法:

在这里插入图片描述

# match查询
GET /items/_search
{"query": {"match": {"name": "脱脂牛奶"}}
}# multi_match查询
GET /items/_search
{"query": {"multi_match": {"query": "牛奶","fields": ["name","category"]}}
}
1.2.2 精确查询

精确查询 ,英文是Term-level query,顾名思义,词条级别的查询。也就是说不会对用户输入的搜索条件在分词,而是作为一个词条,与搜索的字段内容精确值匹配。因此推荐查询keyword、数值、日期、boolean类型的字段。例如id、price、城市、地名、人名等作为一个整体才有含义的字段。

在这里插入图片描述

注意:

#term 所有
GET /items/_search
{"query": {"term": {"name": {"value": "脱脂牛奶"}}}
}

对name进行精确查询,很容易查询不到任何信息。原因是,name是进行分词处理的,属性就是 可分词的文本 ,那么由于脱脂牛奶可以分成两个词语,一个脱脂,一个牛奶,当进行精确查询时,由于此查询中“脱脂牛奶”不分词,因此找不到一个对应的信息,查询结果为空。

在这里插入图片描述

#range 所有
GET /items/_search
{"query": {"range": {"price": {"gt": 10000,"lte": 20000}}}
}
#ids 所有
GET /items/_search
{"query": {"ids": {"values": ["584387","584392"]}}
}

在这里插入图片描述

1.3 复合查询

复合查询大致可以分为两类:

  • 第一类:基于逻辑运算组合叶子查询,实现组合条件,例如:
    • bool
  • 第二类:基于某种运算修改查询时的文档相关性算分,从而改变文档排名。例如:
    • function_score
    • dis_max

布尔查询 是一个或多个查询子句的组合。子查询的组合方式有:

  • must:必须匹配每个子查询,类似“与”
  • should:选择性匹配子查询,类似“或”
  • must_not:必须不匹配,不参与算分,类似“非”
  • filter:必须匹配,不参与算分

在这里插入图片描述

需求: 搜索“智能手机”,但品牌必须是华为,价格是900-1599

GET /items/_search
{"query": {"bool": {"must": [{"match": {"name": "智能手机"}}],"filter": [{"term": {"brand": "华为"}},{"range": {"price": {"gte": 90000,"lte": 159900}}}]}}
}

1.4 排序和分页

elasticsearch支持对搜索结果排序,默认是根据相关度算法(_score)来排序,也可以指定字段排序。可以排序字段类型有:keyword类型、数值类型、地理坐标类型、日期类型等。

在这里插入图片描述

需求: 搜索商品,按照销量排序,销量一样则按照价格升序

# 排序查询
GET /items/_search
{"query": {"match_all": {}},"sort": [{"sold" : "desc"},{"price": "asc"}]
}

elasticsearch默认情况下只返回top10的数据。而如果要查询更对数据就需要修改分页参数了。elasticsearch中通过修改from、size参数来控制要返回的分页结果:

  • from:从第几文档开始
  • size:总共查询几个文档
    在这里插入图片描述

需求: 搜索商品,查询出销量排名前十的商品,销量一样时按照价格升序

 #排序查询
GET /items/_search
{"query": {"match_all": {}},"sort": [{"sold" : "desc"},{"price": "asc"}],"from": 0,"size": 10
}

深度分页问题

elasticsearch的数据一般会采用分片存储,也就是把一个索引中的数据分成N份,存储到不同节点上。查询数据时需要汇总各个分片的数据。

假如要查询第100页数据,每页查10条:

实现思路:

① 对数据排序

② 找出第990-1000名

假如我们现在要查询的是第999页数据呢,是不是要找第9990~10000的数据,那岂不是需要把每个分片中的前10000名数据都查询出来,汇总在一起,在内存中排序?如果查询的分页深度更深呢,需要一次检索的数据岂不是更多?

由此可知,当查询分页深度较大时,汇总数据过多,对内存和CPU会产生非常大的压力。

因此elasticsearch会禁止from+ size 超过10000的请求。

针对深度分页,ES提供了两种解决方案:

  • search after:分页时需要排序,原理是从上一次的排序值开始,查询下一页数据。官方推荐使用的方式
  • scroll:原理将排序数据形成快照,保存在内存。官方已经不推荐使用

search after模式:

  • 优点:没有查询上线,支持深度分页
  • 缺点:只能向后逐页查询,不能随机翻页
  • 场景:数据迁移,手机滚动查询

1.5 高亮显示

高亮显示: 就是在搜索结果中把搜索关键字突出显示。

在这里插入图片描述

# 高亮
GET /items/_search
{"query": {"match": {"name": "脱脂牛奶"}},"highlight": {"fields": {"name": {"pre_tags": "<em>","post_tags": "</em>"}}}
}

在这里插入图片描述

2 JavaRestClient

2.1 快速入门

数据搜索的java代码分成两部分:

  • 构建并发起请求
  • 解析查询结果

在这里插入图片描述

在这里插入图片描述

    @Testvoid testMatchAll() throws IOException {//1. 创建request对象SearchRequest request = new SearchRequest("items");//2. 配置request参数request.source().query(QueryBuilders.matchAllQuery());//3. 发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);System.out.println("response = " + response);}

解析查询结果的API:

在这里插入图片描述

    @Testvoid testMatchAll() throws IOException {//1. 创建request对象SearchRequest request = new SearchRequest("items");//2. 配置request参数request.source().query(QueryBuilders.matchAllQuery());//3. 发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);//4. 解析结果SearchHits searchHits = response.getHits();//4.1 总条数long value = searchHits.getTotalHits().value;System.out.println("value = " + value);//4.2 命中的数据SearchHit[] hits = searchHits.getHits();for (SearchHit hit : hits) {//4.2.1 获取Source的结果String json = hit.getSourceAsString();//4.2.2 处理对象 比如转为ItemDocItemDoc doc = JSONUtil.toBean(json, ItemDoc.class);System.out.println("doc = " + doc);}}

2.2 构建查询条件

在javaRestAPI中,所有类型的query查询条件都是有QueryBuilders来构建的:

在这里插入图片描述

全文检索的查询条件构造API如下:

精确查询的查询条件构造API如下:

在这里插入图片描述

布尔查询的查询条件构造API如下:

在这里插入图片描述

案例

需求:利用javaRestClient实现搜索功能,条件如下:

  • 搜索关键字为脱脂牛奶
  • 品牌必须为德亚
  • 价格必须低于300
    @Testvoid testSearch() throws IOException {//1. 创建request对象SearchRequest request = new SearchRequest("items");//2. 组织DSL参数request.source().query(QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("name","脱脂牛奶")).filter(QueryBuilders.termQuery("brand.keyword","德亚")).filter(QueryBuilders.rangeQuery("price").lt(130000)));//3. 发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);parseResponseResult(response);}

2.3 排序和分页

与query类似,排序和分页参数都是基于request.source()来设置:

在这里插入图片描述

2.4 高亮显示

高亮显示的条件构造API如下:

在这里插入图片描述

高亮显示的结果解析API如下:

在这里插入图片描述

   @Testvoid testHighlight() throws IOException {//1. 创建request对象SearchRequest request = new SearchRequest("items");//2. 组织DSL参数//2.1 query条件request.source().query(QueryBuilders.matchQuery("name", "脱脂牛奶"));//2.2 高亮条件request.source().highlighter(SearchSourceBuilder.highlight().field("name").preTags("<em>").postTags("</em>"));//3. 发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);//4. 解析结果parseHighlightResponseResult(response);}private static void parseHighlightResponseResult(SearchResponse response) {//4. 解析结果SearchHits searchHits = response.getHits();//4.1 总条数long value = searchHits.getTotalHits().value;System.out.println("value = " + value);//4.2 命中的数据SearchHit[] hits = searchHits.getHits();for (SearchHit hit : hits) {//4.2.1 获取Source的结果String json = hit.getSourceAsString();//4.2.2 处理对象 比如转为ItemDocItemDoc doc = JSONUtil.toBean(json, ItemDoc.class);//4.3 处理高亮结果Map<String, HighlightField> hfs = hit.getHighlightFields();if(hfs != null && !hfs.isEmpty()){//4.3.1 根据高亮字段名获取高亮结果HighlightField hf = hfs.get("name");//4.3.2 获取高亮结果,覆盖非高亮结果String hfName = hf.getFragments()[0].string();doc.setName(hfName);}System.out.println("doc = " + doc);}}

3 数据聚合

聚合(aggregations)可以实现对文档数据的统计、分析、运算。运算常见的有三类:

  • 桶(Bucket)聚合:用来对文档做分组
    • TermAggregation:按照文档字段值分组
    • Date Histogram:按照日期阶梯分组,例如一周为一组,或者一月为一组
  • 度量(Metric)聚合:用以计算一些值,比如:最大值、最小值、平均值等
    • Avg:求平均值
    • Max:求最大值
    • Min:求最小值
    • Stats:同时求max、min、avg、sum等
  • 管道(pipeline)聚合:其它聚合的结果为基础做聚合

3.1 DSL聚合

我们要统计所有商品中共有哪些商品分类,其实就是以分类(category)字段对数据分组。category值一样的放在同一组,属于Bucket聚合中的Term聚合。

默认情况下,Bucket聚合是对索引库的所有文档做聚合,我们可以限定要聚合的文档范围,只要添加query条件即可。例如,我想知道价格高于3000元的手机品牌有哪些:

在这里插入图片描述

# 聚合
GET /items/_search
{"query": {"bool": {"filter": [{"term": {"category.keyword": "牛奶"}},{"range": {"price": {"gte": 20000}}}]}}, "size": 0,"aggs": {"brand_agg":{"terms": {"field": "brand.keyword","size": 10}}}
}

除了对数据分组(Bucket)以外,还可以对每个Bucket内的数据进一步做数据计算和统计。例如:我想知道手机有哪些品牌,每个品牌的价格最小值、最大值、平均值。

在这里插入图片描述

# 聚合
GET /items/_search
{"query": {"bool": {"filter": [{"term": {"category.keyword": "牛奶"}},{"range": {"price": {"gte": 20000}}}]}}, "size": 0,"aggs": {"brand_agg":{"terms": {"field": "brand.keyword","size": 10},"aggs": {"price_stats": {"stats": {"field": "price"}}}}}
}

3.2 RestClient聚合

    @Testvoid testAgg() throws IOException {//1. 创建request对象SearchRequest request = new SearchRequest("items");//2. 组织DSL参数//分页request.source().size(0);//聚合条件String brandAggName = "brandAgg";request.source().aggregation(AggregationBuilders.terms(brandAggName).field("brand.keyword").size(10));//3. 发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);//4. 解析结果Aggregations aggregations = response.getAggregations();//4.1 根据聚合名称获取对应的聚合Terms aggregation = aggregations.get(brandAggName);//4.2 获取BucketsList<? extends Terms.Bucket> buckets = aggregation.getBuckets();//4.3 遍历获取每一个bucketfor (Terms.Bucket bucket : buckets) {System.out.println("brand: " + bucket.getKeyAsString());System.out.println("count: " + bucket.getDocCount());}}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 《数据结构(C语言版)第二版》第五章-树和二叉树(5.6 树和森林)
  • 门控循环单元GRU
  • Eclipse 悬浮提示:提高编程效率的利器
  • 基于Springboot的运行时动态可调的定时任务
  • 【Java数据结构】---泛型
  • JVM类加载中的双亲委派机制
  • 智能闹钟能改善睡眠质量吗
  • vue使用响应式API和页面组件ref相同名称问题
  • mysql操作(进阶)
  • 第十二章 元数据管理10分
  • 【C语言】数组与指针常见笔试题讲解(1)
  • MySQL 5.7使用 GTID 和 Binlog高可用方案
  • Nginx 常用配置
  • ctfshow-web入门-sql注入(web186-web190)
  • python后端 启用 gzip 压缩响应体
  • 《剑指offer》分解让复杂问题更简单
  • 【挥舞JS】JS实现继承,封装一个extends方法
  • Bytom交易说明(账户管理模式)
  • iOS编译提示和导航提示
  • Java新版本的开发已正式进入轨道,版本号18.3
  • JS 面试题总结
  • LeetCode29.两数相除 JavaScript
  • Median of Two Sorted Arrays
  • opencv python Meanshift 和 Camshift
  • PyCharm搭建GO开发环境(GO语言学习第1课)
  • QQ浏览器x5内核的兼容性问题
  • React 快速上手 - 06 容器组件、展示组件、操作组件
  • SpiderData 2019年2月16日 DApp数据排行榜
  • Sublime Text 2/3 绑定Eclipse快捷键
  • XML已死 ?
  • 阿里云爬虫风险管理产品商业化,为云端流量保驾护航
  • 多线程事务回滚
  • 关于List、List?、ListObject的区别
  • 一个SAP顾问在美国的这些年
  •  一套莫尔斯电报听写、翻译系统
  • 你学不懂C语言,是因为不懂编写C程序的7个步骤 ...
  • 说说我为什么看好Spring Cloud Alibaba
  • ​Python 3 新特性:类型注解
  • # 执行时间 统计mysql_一文说尽 MySQL 优化原理
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • $(selector).each()和$.each()的区别
  • (02)vite环境变量配置
  • (11)MATLAB PCA+SVM 人脸识别
  • (14)学习笔记:动手深度学习(Pytorch神经网络基础)
  • (4) PIVOT 和 UPIVOT 的使用
  • (C#)获取字符编码的类
  • (PySpark)RDD实验实战——取最大数出现的次数
  • (二)什么是Vite——Vite 和 Webpack 区别(冷启动)
  • (附源码)springboot掌上博客系统 毕业设计063131
  • (机器学习-深度学习快速入门)第三章机器学习-第二节:机器学习模型之线性回归
  • (蓝桥杯每日一题)平方末尾及补充(常用的字符串函数功能)
  • (论文阅读32/100)Flowing convnets for human pose estimation in videos
  • (篇九)MySQL常用内置函数
  • (深度全面解析)ChatGPT的重大更新给创业者带来了哪些红利机会
  • (十)c52学习之旅-定时器实验