提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
这里对项目中添加ES服务做一个总结,从0到添加ES到项目中。一、框架分析
使用ES做查询的话,他最好的地方就是不再走数据库,这样减少了数据库访问资源,同时有倒排索引的存在,查询会非常的快。
图例解析
二、环境搭建
1.ElasticSearch的下载安装
2.Logstash的下载安装
传送门
这里环境的搭建个人人为是蛮麻烦的。所以单独为其写了博客。
当环境搭建好之后,本地应该有ES的服务端,包括IK分词依赖,Head插件。还有Logstash的服务端,包括LogStash-input-jdbc的插件。
2.数据的同步
这里在前面一篇里已经有了介绍,然后由于系统有多个模块,这里是想将多个模块的数据同步到一起,就是将多个表的数据同步到一个表,这里原理就是将多个表查询的字段设置一个别名,别名保持一致。即可将多个表同步到一个ES索引中,这样就可以查询的时候查询一个索引获取所有的数据。后来考虑到性能开销以及后续可能这个索引会很大,还是采用了多个索引的模式。即先建立一个数据模板,后续各个表查询别名还是一致,不过同步到的是多个索引中。
到这里环境就ok了,数据也同步好了,
三、查询
查询的话,贴一下主要代码
// 条件搜索
SearchRequest searchRequest = new SearchRequest(indices);
// searchSourceBuilder将查询转换为es的查询语句
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
// 使用BoolQueryBuilder对象(复杂查询)
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
// 分页
searchSourceBuilder.from(paramDTO.getPageNo() * paramDTO.getPageSize());
searchSourceBuilder.size(paramDTO.getPageSize());
// 分词匹配查询
//MatchQueryBuilder termQueryBuilder = QueryBuilders.matchQuery("title", keyWord);
MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(keyWord, "title", "description")
.type(MultiMatchQueryBuilder
.Type.BEST_FIELDS);
// 精准匹配(不分词)
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("delete_flag", 0);
// 使用constantScoreQuery查询不计入得分
ConstantScoreQueryBuilder constantScoreQueryBuilder = QueryBuilders.constantScoreQuery(termQueryBuilder);
boolQueryBuilder.must(multiMatchQueryBuilder)
.must(constantScoreQueryBuilder);
searchSourceBuilder.query(boolQueryBuilder);
searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
// es查询默认只返回10条,需要给定数量
// searchSourceBuilder.size(1000);
// 高亮
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("title");
highlightBuilder.field("description");
highlightBuilder.requireFieldMatch(false);
highlightBuilder.preTags("<span style='color:red;font-weight:900'>");
highlightBuilder.postTags("</span>");
searchSourceBuilder.highlighter(highlightBuilder);
System.out.println(searchSourceBuilder.toString());
// 执行搜索
searchRequest.source(searchSourceBuilder);
SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 解析结果
List<Map<String, Object>> list = new ArrayList<>();
for (SearchHit hit : search.getHits().getHits()) {
// 解析高亮字段
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
HighlightField title = highlightFields.get("title");
Map<String, Object> sourceAsMap = hit.getSourceAsMap();// 原数据
// 解析 将原来的字段替换为我们高亮的字段
if (title != null) {
Text[] fragments = title.fragments();
String nTitle = "";
for (Text text : fragments) {
nTitle += text;
}
sourceAsMap.put("title", nTitle);
}
HighlightField description = highlightFields.get("description");
if (description != null) {
Text[] fragments = description.fragments();
String nDescription = "";
for (Text text : fragments) {
nDescription += text;
}
sourceAsMap.put("description", nDescription);
}
sourceAsMap.put("score", hit.getScore());
list.add(sourceAsMap);
}
// 对查询到的分数进行缩放处理
Float[] orgData = new Float[list.size()];
for (int i = 0; i < list.size(); i++) {
orgData[i] = (Float) list.get(i).get("score");
}
Float[] newData = new Float[list.size()];
if (paramDTO.getPageSize().equals(5)) {
newData = dataZoom(orgData, 60, 100);
} else {
long pages = search.getHits().getTotalHits().value / paramDTO.getPageSize(); // 有多少页
pages = pages == 0 ? 2 : pages;
long avePages = 100 / pages; //每页的区间
newData = dataZoom(orgData, (int) (100 - ((paramDTO.getPageNo() + 1) * avePages)), (int) (100 - ((paramDTO.getPageNo()) * avePages)));
}
for (int i = 0; i < list.size(); i++) {
list.get(i).put("score", newData[i]);
}
date.setData(list);
// 将总数放入
date.setTotal(search.getHits().getTotalHits().value);
return date;
数据的缩放
/**
* 对数据进行缩放处理
*
* @param: orgData 源数据 minSection 区间最小值 maxSection 区间最大值
* @return: java.lang.Float[]
* @author PengG
* @date: 2020/12/7 10:59
*/
private Float[] dataZoom(Float[] orgData, int minSection, int maxSection) {
Float[] newData = new Float[orgData.length];
for (int i = 0; i < orgData.length; i++) {
// 数据归一化
Float tmp = (orgData[i] - orgData[orgData.length - 1]) / (orgData[0] - orgData[orgData.length - 1]);
// 数据缩放
newData[i] = minSection + tmp * (maxSection - minSection);
}
return newData;
}
总结
到这里项目中添加ES服务就结束了,其实这里一想还是很简单的,关键要知道有哪些东西,不要走弯路,像我中间就使用过canel同步过数据,结果整了很久效果还不是很理想,后来换了logstash之后,才发现人家配套的用起来真香。同时要结合项目需求,慢慢摸索这些中间件还是很耗时间的,后续有新鲜的东西再继续完善