SpringBoot集成Elasticsearch实例
SpringBoot项目集成Elasticsearch实例
导包
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
配置es连接
spring:data:elasticsearch:cluster-name: elasticsearchcluster-nodes: 127.0.0.1:9300
准备query接收查询条件
@Data
public class CarSearchQuery extends BaseQuery {private Long carType;private Double maxPrice;private Double minPrice;//0 以下 1 以上private Integer carAgeType;private Integer carAge;//是否超值private Integer costEffective;//急售private Integer rushSale;//准新车private Integer quasiNewCar;//可迁全国private Integer transitiveCountry;//排序字段private String sortField;//排序类型 desc降序 asc升序号private String sortType;private Double longitude;private Double latitude;private Double distance;private Long shopId;
}
准备Controller
@RestController
@RequestMapping("/car/search")
public class CarSearchController {@Autowiredprivate ICarSearchService carSearchService;@PostMappingpublic AjaxResult search(@RequestBody CarSearchQuery query) {PageList<CarDoc> search = carSearchService.search(query);return AjaxResult.me().setData(search);}
}
定义Document文档类型
@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(indexName = "example-car", type = "car")
public class CarDoc {@Idprivate Long id;@Field(type = FieldType.Text, analyzer = "ik_smart", searchAnalyzer = "ik_smart")private String title;@Field(type = FieldType.Keyword)private String cover;@Field(type = FieldType.Double)private BigDecimal salePrice;@Field(type = FieldType.Double)private BigDecimal costPrice;@Field(type = FieldType.Integer)private Integer isNew;@Field(type = FieldType.Date)private Date registerTime;@Field(type = FieldType.Double)private Double mileAge;@Field(type = FieldType.Long)private Long shopId;@MultiField(mainField = @Field(type = FieldType.Text, analyzer = "ik_smart", searchAnalyzer = "ik_smart"),otherFields = {@InnerField(type = FieldType.Keyword, suffix = "keyword")})private String shopName; // @MultiField对同一字段应用不同的分析器或存储策略,这里既可以将该字段按照text进行拆分,也可以作为keyword进行查询@Field(type = FieldType.Keyword)private String shopAddress;@Field(type = FieldType.Date)private Date onSaleTime;@Field(type = FieldType.Integer)private Integer costEffective;@Field(type = FieldType.Integer)private Integer rushSale;@Field(type = FieldType.Integer)private Integer quasiNewCar;@Field(type = FieldType.Integer)private Integer transitiveCountry;@Field(type = FieldType.Long)private Long typeId;@MultiField(mainField = @Field(type = FieldType.Text, analyzer = "ik_smart", searchAnalyzer = "ik_smart"),otherFields = {@InnerField(type = FieldType.Keyword, suffix = "keyword")})private String typeName; @Field(type = FieldType.Text, analyzer = "ik_smart", searchAnalyzer = "ik_smart")private String carInfo;@GeoPointField // 表示坐标类型private GeoPoint shopPoint;
}
准备一个Repository接口
@Repository
public interface CarDocRepository extends ElasticsearchRepository<CarDoc, Long> {
}// 接口中的泛型,一个是文档对象的类型,一个是文档对象id的类型
使用spring-boot-starter-data-elasticsearch对es进行操作时也要按照es请求的格式进行操作
{"query": {"bool": {"must": {"match_all": {}},"filter": {"term": {"username": "Steven King"}}}}
}
查询
@Service
public class CarSearchServiceImpl implements ICarSearchService {@Autowiredprivate CarDocRepository repository;@Autowiredprivate HighlightResultMapper highlightResultMapper;@Autowiredprivate ElasticsearchTemplate elasticsearchTemplate;@Overridepublic PageList<CarDoc> search(CarSearchQuery query) {NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();BoolQueryBuilder boole = QueryBuilders.boolQuery(); // 外层的boolList<QueryBuilder> filter = boole.filter(); // 内层的fitlerList<QueryBuilder> must = boole.must(); // 内层的must// 查询"title", "typeName", "shopName", "carInfo"中有查询关键字的结果if (StringUtils.isNotBlank(query.getSearch())) {must.add(QueryBuilders.multiMatchQuery(query.getSearch(), "title", "typeName", "shopName", "carInfo"));}if (Objects.nonNull(query.getShopId())) {filter.add(QueryBuilders.termQuery("shopId", query.getShopId()));}// 进行范围查询if (Objects.nonNull(query.getMinPrice())) {filter.add(QueryBuilders.rangeQuery("costPrice").gte(query.getMinPrice()));}if (Objects.nonNull(query.getMaxPrice())) {filter.add(QueryBuilders.rangeQuery("costPrice").lte(query.getMaxPrice()));}// 按时间进行查找if (Objects.nonNull(query.getCarAge())) {Date date = DateUtils.addYears(new Date(), (-query.getCarAge()));if (query.getCarAgeType() == 1) {filter.add(QueryBuilders.rangeQuery("registerTime").lt(date.getTime()));}if (query.getCarAgeType() == 0) {filter.add(QueryBuilders.rangeQuery("registerTime").gte(date.getTime()));}}// 经纬度Double lon = query.getLongitude();Double lat = query.getLatitude();// 按照经纬度计算距离并按照距离进行查询if (Objects.nonNull(lon) && Objects.nonNull(lat) && Objects.nonNull(query.getDistance())) {GeoDistanceQueryBuilder point = QueryBuilders.geoDistanceQuery("shopPoint").point(lat, lon).distance(query.getDistance(), DistanceUnit.KILOMETERS);filter.add(point);}// 将bool加入到最外层query的构造器builder.withQuery(boole);SortOrder order = SortOrder.ASC;if (!"asc".equals(query.getSortType())) {order = SortOrder.DESC;}// 通过指定字段进行排序if (Objects.nonNull(query.getSortField())) {FieldSortBuilder sort = SortBuilders.fieldSort(query.getSortField()).order(order);builder.withSort(sort);} else {// 没传则默认按照距离排序if (Objects.nonNull(lat) && Objects.nonNull(lon)) {GeoDistanceSortBuilder point = new GeoDistanceSortBuilder("shopPoint", lat, lon);GeoDistanceSortBuilder sort = point.order(order);builder.withSort(sort);}}// 高亮展示,通过给字段前后加html标签的方式实现高亮等效果,需要一个高亮的工具类HighlightBuilder.Field title = new HighlightBuilder.Field("title").preTags("<span style='color:red'>").postTags("</span>");builder.withHighlightFields(title);// 进行分页展示builder.withPageable(PageRequest.of(query.getCurrentPage() - 1, query.getPageSize()));TermsAggregationBuilder aggBuilders1 = AggregationBuilders.terms("typeIdGroup").field("typeId").order(BucketOrder.count(true)).subAggregation(AggregationBuilders.terms("typeNameGroup").field("typeName.keyword").order(BucketOrder.count(true)));// 聚合查询builder.addAggregation(aggBuilders1);AggregatedPage<CarDoc> carDocs = elasticsearchTemplate.queryForPage(builder.build(), CarDoc.class, highlightResultMapper);Map<String, Object> map = SearchUtil.handleTermsAggsData(carDocs.getAggregations());Long counts = carDocs.getTotalElements();List<CarDoc> content = carDocs.getContent();for (CarDoc doc : content) {String s = doc.getShopAddress();if (StringUtils.isNotBlank(s)) {String string = s.split("市")[0] + "市";}doc.setShopAddress(s);}return new PageList<>(counts, content, map);}
}
PageList
@Data
public class PageList<T> {private Long count;private List<T> data; // 用于存放聚合查询的数据private Map<String,Object> map;public PageList() {}public PageList(Long count, List<T> data, Map<String, Object> map) {this.count = count;this.data = data;this.map = map;}public PageList(Long count, List<T> data) {this.count = count;this.data = data;}
}
高亮结果映射器
@Component
public class HighlightResultMapper implements SearchResultMapper {@Overridepublic <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> aClass, Pageable pageable) {// 记录总条数long totalHits = response.getHits().getTotalHits();// 记录列表(泛型) - 构建Aggregate使用List<T> list = new ArrayList<>();// 获取搜索结果(真正的的记录)SearchHits hits = response.getHits();for (SearchHit hit : hits) {if(hits.getHits().length <= 0){return null;}// 将原本的JSON对象转换成Map对象Map<String, Object> map = hit.getSourceAsMap();// 获取高亮的字段MapMap<String, HighlightField> highlightFields = hit.getHighlightFields();for (Map.Entry<String, HighlightField> highlightField : highlightFields.entrySet()) {// 获取高亮的KeyString key = highlightField.getKey();// 获取高亮的ValueHighlightField value = highlightField.getValue();// 实际fragments[0]就是高亮的结果,无需遍历拼接Text[] fragments = value.getFragments();StringBuilder sb = new StringBuilder();for (Text text : fragments) {sb.append(text);}// 因为高亮的字段必然存在于Map中,就是key值// 可能有一种情况,就是高亮的字段是嵌套Map,也就是说在Map里面还有Map的这种情况,这里没有考虑map.put(key, sb.toString());}// 把Map转换成对象T item = JSONObject.parseObject(JSONObject.toJSONString(map),aClass);list.add(item);}// 返回的是带分页的结果return new AggregatedPageImpl<>(list, pageable, totalHits,response.getAggregations()); //获取聚合结果}@Overridepublic <T> T mapSearchHit(SearchHit searchHit, Class<T> aClass) {return null;}
}
搜索工具类,用于处理聚合查询结果
public class SearchUtil {/*** 处理terms聚合 id name* @param aggregations* @return*/public static Map<String, Object> handleTermsAggsData(Aggregations aggregations) {// 获取聚合查询结果Map<String, Aggregation> aggregationsMap = aggregations.getAsMap();Set<Map.Entry<String, Aggregation>> entries = aggregationsMap.entrySet();Iterator<Map.Entry<String, Aggregation>> iterator = entries.iterator();//6.1有多少聚合就要返回多少个key-List<IdName>Map<String, Object> aggsData = new HashMap<>();while (iterator.hasNext()) {Map.Entry<String, Aggregation> entry = iterator.next();String key = entry.getKey();System.out.println(key);Aggregation aggsId = entry.getValue();if (aggsId instanceof LongTerms) { //6.2 拿到id聚合,并且必须是LongTermsLongTerms aggsIdLong = (LongTerms) aggsId;List<LongTerms.Bucket> buckets = aggsIdLong.getBuckets();//6.3 List<IdName<Long,String>List<IdName> list = new ArrayList<>();buckets.forEach(bucket -> {String idStr = bucket.getKeyAsString();//6.4 通过子聚合获取nameMap<String, Aggregation> subAggs = bucket.getAggregations().getAsMap();Set<Map.Entry<String, Aggregation>> entries1 = subAggs.entrySet();//直接获取第一个Map.Entry<String, Aggregation> nameAggEntry = entries1.iterator().next();Aggregation nameAgg = nameAggEntry.getValue();if (nameAgg instanceof StringTerms) {StringTerms nameAggStringTerms = (StringTerms) nameAgg;String nameStr = nameAggStringTerms.getBuckets().get(0).getKeyAsString();IdName idName = new IdName();idName.setId(Long.valueOf(idStr));idName.setName(nameStr);list.add(idName);}});aggsData.put(key, list);}}return aggsData;}
}
相关文章:
SpringBoot集成Elasticsearch实例
SpringBoot项目集成Elasticsearch实例 导包 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency>配置es连接 spring:data:elasticsearch:cluster…...
2024.ZCPC.M题 计算三角形个数
题目描述: 小蔡有一张三角形的格子纸,上面有一个大三角形。这个边长为 的大三角形, 被分成 个边长为 1 的小三角形(如图一所示)。现在,小蔡选择了一条水平边 删除(如图二所示),请你找出图上剩余…...
Java常见设计模式入门与实践
设计模式是软件开发中被反复应用的、为解决特定问题而总结出的最佳实践。它们提供了开发可重用、灵活和高效软件系统的方法。在Java中,设计模式可以帮助开发者编写更高质量的代码。以下是Java中一些常用设计模式的入门介绍及其实践示例。 1. 单例模式 (Singleton P…...
110.平衡二叉树
给定一个二叉树,判断它是否是 平衡二叉树 题解:平衡二叉树 是指该树所有节点的左右子树的深度相差不超过 1。可以采用递归遍历每一个节点,得到其高度,在判断高度时不可避免的要用到其左右子树的高度,所以可以顺便判断出…...
字符串数组——传递文本的不同方法实例
一、实例化一个文本并在文本上直接显示接收的信息 1、制作一个预制体 (1) UI-Text (TMP),TitleText (2) 给Text (TMP)添加Recipients.cs组件 using System.Collections; using System.Collections.Generic; using TMPro; using UnityEngine;public class Recipi…...
JDBC简介
JDBC最基本的知识点要求理解并会使用下边的两个案例即可: 前言: Jdbc操作步骤简析: 1.Connection connDriverManager.getConnection(url,账号,密码):用DriverManager类的连接方法根据url账号密码连接数据库…...
RK3568平台(触摸篇)触摸屏基本原理
一.触摸屏概述 触摸屏作为一种新的输入设备,它是目前最简单、方便、自然的一种人机交互方式。 触摸屏又称为“触控屏”、“触控面板”,是一种可接收触头等输入讯号的感应式液晶显示装置;当接触了屏幕上的图形按钮时,屏幕上的触觉…...
【太原理工大学】软件系统安全—分析题
OK了,又是毫无准备的一场仗,我真是ありがとうございます 凸^o^凸 根据前几年传下来的信息,所谓“分析”,就是让你根据情节自行设计,例如如何设计表单等,这类多从实验中出,王老师强调好好做实验一…...
【仪器仪表/电源专题】浮地信号的测试的四种方案对比
接地信号和浮地信号区别 所有的电压测量都是差分测量,差分测量定义为两点之间的电压差。所以会分成两类: 1.参考地电平测量(有时也叫接地信号) 2.非参考地电平测量(也称为浮地测量) 测试信号可以分为接地信…...
Centos7安装jdk8或11以及切换方案
目录 jdk安装 安装OpenJDK11 安装OpenJDK8 配置默认的 Java 版本 验证 全局环境变量(选配) 个人版(自己可以用,公司不建议) 公司版本 /etc/profile 和 ~/.bash_profile 区别 前言-与正文无关 生活远不止眼前的苦…...
计算机二级Access选择题考点—代码篇
第1题 窗体的事件过程如下: Private Sub Form MouseDown(Button As Integer ,Shift As integer,X As Single,Y As Single)If Shift 6 And Button 2 Then MsgBox "Hello World."End lf End Sub程序运行后,要在窗体消息框中显示"Hello World."…...
海外仓系统如何让海外仓受益,WMS海外仓系统使用指南
随着跨境电商业务的快速发展,海外仓面临着需要更加高速运转的巨大挑战。 当海外仓出现因为手动作业导致效率低下,成本不断飙升或者出现库存管理问题的时候,意味着是时候引入一套合适的海外仓管理系统了。 对于寻求海外仓业务流程优化的企业…...
贪心-区间问题
135. 分发糖果 问题描述 n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。 你需要按照以下要求,给这些孩子分发糖果: 每个孩子至少分配到 1 个糖果。相邻两个孩子评分更高的孩子会获得更多的糖果。 请你给每个孩子分发糖果&#x…...
算法分析与设计期末考试复习GDPU
重点内容: 绪论: 简单的递推方程求解 1.19(1)(2) 、 教材例题 多个函数按照阶的大小排序 1.18 分治法: 分治法解决芯片测试问题 计算a^n的复杂度为logn的算法(快速幂) 分治法解决平面最近点对问…...
分批次训练和评估神经网络模型
【背景】 训练神经网络模型的时候,特征组合太多,电脑的资源会不足,所以采用分批逐步进行。已经处理过的批次保存下来,在下一次跳过,只做新加入的批次训练。 选择最优模型组合在中间结果的范围内选择,这样…...
【CS.AL】算法核心之分治算法:从入门到进阶
文章目录 1. 概述2. 适用场景3. 设计步骤4. 优缺点5. 典型应用6. 题目和代码示例6.1 简单题目:归并排序6.2 中等题目:最近点对问题6.3 困难题目:分数背包问题 7. 题目和思路表格8. 总结References 1000.01.CS.AL.1.4-核心-DivedeToConquerAlg…...
leetcode刷题记录:hot100强化训练2:二叉树+图论
二叉树 36. 二叉树的中序遍历 递归就不写了,写一下迭代法 class Solution(object):def inorderTraversal(self, root):""":type root: TreeNode:rtype: List[int]"""if not root:return res []cur rootstack []while cur or st…...
湘潭大学信息与网络安全复习笔记2(总览)
前面的实验和作业反正已经结束了,现在就是集中火力把剩下的内容复习一遍,这一篇博客的内容主要是参考教学大纲和教学日历 文章目录 教学日历教学大纲 教学日历 总共 12 次课,第一次课是概述,第二次和第三次课是密码学基础&#x…...
C语言:头歌使用函数找出数组中的最大值
任务描述 本关任务:本题要求实现一个找出整型数组中最大值的函数。 函数接口定义: int FindArrayMax( int a[], int n ); 其中a是用户传入的数组,n是数组a中元素的个数。函数返回数组a中的最大值。 主程序样例: #include <stdio.h>#…...
【技巧】Leetcode 191. 位1的个数【简单】
位1的个数 编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中 设置位 的个数(也被称为汉明重量)。 示例 1: 输入:n 11 输出:3 解释&#x…...
SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
