由于上一遍博客中elasticsearch5.x在linux上分布式安装(多节点) 装的elasticsearch服务比较新,所以将elasticsearch单独做成一个服务运行,需要用的时候用路由转发请求这个服务。
因为elasticsearch版本比较新,所以用到了spring data的里程版本,具体的pom.xml配置和当前这个项目 可以去我github主页下载(https://github.com/lh2420124680/ElasticServer)。
elasticsearch底层用的是lucene,它的搜索速度是非常快的。
在实际的应用中我们有两种部署方案,分别应对不同的业务场景:
①实时保存数据入索引库
当用户保存数据的时候,保存一份到数据库中,当数据库保存成功后,将保存的数据发送到消息队里中(本项目中的消息中间件用的是activeMQ),然后当消息队列监听到有消息发过过来的时候,接受到消息,也就是接受到保存的数据,然后消息监听器执行elasticsearch方法将保存到数据库中的数据同时也保存到对应的索引库中。这种方法对原来的代码侵入少,因为elasticsearch的服务是单独的一个项目。
流程:前端将要插入的数据发送给后台 -> 插入数据库成功 -> 前端执行发送消息队列的方法 -> 发送的数据进入消息队列 -> 消息监听器接收到消息后将数据插入到对应的索引库中。
本方法适用查询实时性并且结构简单的数据。
②每天定时从数据库中将数据同步到索引库中。
这种方法需要用到elastic旗下的一些插件,可以参考本博客中的 elasticsearch与oracle数据库数据同步
本方法适用查询非实时性但结构复杂的数据。
本篇博客主要用的是第一个方法,对spring data中的ElasticsearchTemplate进行了重构,因为ElasticsearchTemplate对于返回值类型依赖实体,并且实体需要用@document注解才能使用,所以本项目中对ElasticsearchTemplate源码进行了重构,将发送参数改为json对象的字符串,返回结果为List<Map>这样的类型,这样就不用每次做新业务时要用到elasticsearch的时候去新增当前业务实体从而去修改代码,重构后只用一次部署,后面就可以适用多个业务场景。
下面会列出一些需要注意的点,需要深入研究的朋友可以去我的githib上下载该项目(https://github.com/lh2420124680/ElasticServer)。
elasticsearch主要的配置文件:com-zlb-elastic.xml
这里我没有用ElasticsearchTemplate,而是用的自定义的elasticObjectTemplate类,让这个类继承ElasticsearchTemplate类,然后重写父类。
然后修改了ElasticsearchTemplate类中的queryForList方法。(父类中的只有查询对象和实体对象两个参数)
本项目v1.0只是对单个插入到索引库的方法进行了重构,后面会慢慢重构ElasticsearchTemplate所有的主要方法。
这里我们需要将传过来的json对象转为object数组,因为父类中会用到
另外我们还需要重构一个类ResultsMapper,用于索引的返回结果对象。
ResultsMapper是用于ElasticsearchTemplate类中返回结果对象的处理类,他返回的List为传输过来的实体泛型,例如当我查询的时候传输后来为Man类,那么他返回就是List<Man>,因为本次重构去掉了实体,用Map来代替实体模型,所以我们也许需要重写ResultsMapper类,但是ResultsMapper是一个接口,我们找到DefaultResultMapper类实现了这个ResultsMapper接口,所有我们重写一个DefaultResultObjectMapper类去继承DefaultResultMapper这个类,然后主要重写mapEntity方法。
以上就是对源码的重写的一些要点,虽然说的不是很清楚,但是看过几遍ElasticsearchTemplate的源码就会理解。
消息监听器,监听到数据就调用自定义的ElasticObjectTemplate方法去插入到索引库中。
package com.zjy.jms;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zjy.biz.ElasticBiz;
import com.zjy.helper.ElasticObjectTemplate;
import com.zjy.helper.EscapeHelper;
import com.zjy.helper.StringUtils;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
@Component
public class ElasticReceiver implements MessageListener {
private ElasticObjectTemplate elasticObjectTemplate;
public ElasticObjectTemplate getElasticObjectTemplate() {
return elasticObjectTemplate;
}
public void setElasticObjectTemplate(ElasticObjectTemplate elasticObjectTemplate) {
this.elasticObjectTemplate = elasticObjectTemplate;
}
public void onMessage(Message message) {
try {
String msg = ((TextMessage) message).getText();
String data = java.net.URLDecoder.decode(msg, "UTF-8");
String unescape = EscapeHelper.unescape(data);
JSONObject parseObject = JSON.parseObject(unescape);
String dataId = StringUtils.GetGUID();
String indexName = parseObject.getString("indexName");
String typeName = parseObject.getString("typeName");
String entity = parseObject.getString("entity");
IndexQuery indexQuery = new IndexQueryBuilder().withId(dataId).withIndexName(indexName).withType(typeName).withObject(entity).build();
String index = elasticObjectTemplate.index(indexQuery);
System.out.println("indexName:"+indexName + index);
} catch (JMSException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
elasticsearch查询,删除的服务接口。
package com.zjy.service;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSON;
import com.zjy.helper.DataConvertHelper;
import com.zjy.helper.ElasticObjectTemplate;
import com.zjy.helper.EscapeHelper;
import com.zjy.helper.ListResult;
import com.zjy.helper.StringUtils;
@RestController
@RequestMapping(value = "/ElasticService")
public class ElasticService {
@Autowired
private ElasticObjectTemplate elasticObjectTemplate;
/**
* @param request
* @return
*/
@RequestMapping(value = "/queryResource.ashx", method = RequestMethod.GET)
public ListResult<Map<String, Object>> queryResource(HttpServletRequest request) {
Map<String, Object> where = DataConvertHelper.getRequestParams(request);
String indexName = where.get("indexName").toString();
String typeName = where.get("typeName").toString();
// 创建搜索条件对象(条件 参数名 + "_jz" 为精准匹配, 参数名 + "_mh" 为模糊匹配)
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
String key = "";
String value = "";
String mode = "";
String reallyParam = "";
for(Map.Entry<String, Object> map : where.entrySet()) {
key = map.getKey();
value = map.getValue().toString();
mode = key.substring(key.length()-3);
reallyParam = key.substring(0, key.length()-3);
if ("_jz".equals(mode)) { // 该条件为精准查询
boolQuery.must(QueryBuilders.termQuery(reallyParam, value));
} else if ("_mh".equals(mode)) { // 该条件为模糊查询
boolQuery.must(QueryBuilders.matchQuery(reallyParam, value));
}
}
// 创建排序对象 (0是倒叙,1是正序)
Object sort = where.get("sort");
Object sortType = where.get("sortType");
SortBuilder sortBuilder = null;
if (!StringUtils.IsEmptyOrNull(sort) && !StringUtils.IsEmptyOrNull(sortType)) {
if ("0".equals(sortType)) { // 倒叙
sortBuilder = SortBuilders.fieldSort(sort.toString()).order(SortOrder.DESC);
} else { // 正序
sortBuilder = SortBuilders.fieldSort(sort.toString()).order(SortOrder.ASC);
}
}
// 分页数据
int pageIndex = StringUtils.IsEmptyOrNull(where.get("pageIndex")) ? 1 : Integer.valueOf(where.get("pageIndex").toString());
int pageSize = StringUtils.IsEmptyOrNull(where.get("pageSize")) ? 10 : Integer.valueOf(where.get("pageSize").toString());
// 创建SearchQuery查询对象 判断排序对象是否空,是空就不创建排序对象
SearchQuery searchQuery = null;
if (sortBuilder == null) {
searchQuery = new NativeSearchQueryBuilder()
.withQuery(boolQuery)
.withPageable(PageRequest.of((pageIndex-1)*pageSize, pageSize))
.build();
} else {
searchQuery = new NativeSearchQueryBuilder()
.withQuery(boolQuery)
.withSort(sortBuilder)
.withPageable(PageRequest.of(pageIndex, pageSize))
.build();
}
List<Map<String, Object>> list = elasticObjectTemplate.queryForList(searchQuery, indexName, typeName);
searchQuery = new NativeSearchQueryBuilder()
.withQuery(boolQuery)
.withIndices(indexName)
.withTypes(typeName)
.build();
long count = elasticObjectTemplate.count(searchQuery);
ListResult<Map<String, Object>> result = new ListResult<Map<String, Object>>();
result.setRows(list);
result.setTotal((int)count);
result.setPageindex(pageIndex);
result.setPages(pageSize);
return result;
}
@RequestMapping(value = "/delete.ashx", method = RequestMethod.POST)
public boolean insert(HttpServletRequest request) {
Map<String, Object> where = DataConvertHelper.getRequestParams(request);
String indexName = where.get("indexName").toString();
String typeName = where.get("typeName").toString();
String gid = where.get("gid").toString();
elasticObjectTemplate.delete(indexName, typeName, gid);
return false;
}
}
对于前端传输的参数的接口规则可以参考我写的elasticsearch服务api接口文档。(文档地址见图下面的链接)
elasticsearch服务api接口文档下载地址:链接:https://pan.baidu.com/s/1bap8LsjH-GkoT2xJuWZcsw 密码:6tn3
代码地址:https://github.com/lh2420124680/ElasticServer