一、项目介绍
最近一直在弄Elasticsearch,所以学习了下Spring整合Elasticsearch的TransportClient客户端,使用的是spring提供的@Configuration注解来管理 TransportClient客户端,具体如下:
TransportClient客户端配置实体类:
package com.fendo.config; import java.net.InetAddress; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.transport.client.PreBuiltTransportClient; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; public class TransportClientFactory implements FactoryBean<TransportClient>,InitializingBean,DisposableBean{ private String clusterName; private String host; private int port; private TransportClient client; public void setClusterName(String clusterName) { this.clusterName = clusterName; } public void setHost(String host) { this.host = host; } public void setPort(int port) { this.port = port; } @Override public void destroy() throws Exception { if(client!=null) client.close(); } @Override public void afterPropertiesSet() throws Exception { Settings settings=Settings.builder().put("cluster.name",this.clusterName).build(); client=new PreBuiltTransportClient(settings).addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(this.host),this.port)); } @Override public TransportClient getObject() throws Exception { return client; } @Override public Class<?> getObjectType() { return TransportClient.class; } @Override public boolean isSingleton() { return false; } }
TransportClient管理类:
package com.fendo.config; import java.util.LinkedHashSet; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; import org.springframework.stereotype.Controller; import org.springframework.transaction.annotation.EnableTransactionManagement; /** * @author fendo * */ @Configuration @ComponentScan(basePackages = {"com.fendo"}, excludeFilters = {@ComponentScan.Filter(type= FilterType.ANNOTATION,value = Controller.class)}) @EnableTransactionManagement public class SpringConfiguration { //bean的id为transportClient @Bean public TransportClientFactory transportClient(){ TransportClientFactory transportClientFactory=new TransportClientFactory(); transportClientFactory.setClusterName("my-application"); transportClientFactory.setHost("localhost"); transportClientFactory.setPort(9300); return transportClientFactory; } }
然后在Service实现类中通过一下方式注入进来使用:
@Autowired private TransportClient transportClient;
首页搜索页面如下所示
能对搜索的关键字实现高亮显示
二、原理分析
实现代码如下,由于只是个简单的搜索,代码写得也是很简单。。。
package com.fendo.service.impl; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.common.text.Text; import org.elasticsearch.index.query.MatchAllQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryStringQueryBuilder; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder; import org.elasticsearch.search.fetch.subphase.highlight.HighlightField; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.fasterxml.jackson.databind.ObjectMapper; import com.fendo.common.Page; import com.fendo.entity.CsdnBlog; import com.fendo.service.CsdnBlogService; import net.sf.json.JSONObject; @Service public class CsdnBlogServiceImpl implements CsdnBlogService{ @Autowired private TransportClient transportClient; private static int num = 0; private static final String IndexName="csdnblog"; private static final String TypeName="article"; public static final Logger LOGGER = Logger.getLogger(CsdnBlogServiceImpl.class); private static ObjectMapper mapper = new ObjectMapper(); @Override public Page search(String param,Integer pageSize,Integer pageNo,String type) throws Exception { QueryBuilder queryBuilders=null; Page page=new Page(); param = null==param?"":param; pageNo = null==pageNo?1:pageNo; pageSize = null==pageSize?15:pageSize; page.setPageNo(pageNo); page.setPageSize(pageSize); long start = System.currentTimeMillis(); HighlightBuilder hiBuilder=new HighlightBuilder().field("*").requireFieldMatch(false); hiBuilder.preTags("<span style=/"color:red/">"); hiBuilder.postTags("</span>"); //查询所有 if("All".equals(type)){ if(!"".equals(param)&¶m!=null){ queryBuilders = QueryBuilders.queryStringQuery(param); //设置高亮显示 // hiBuilder=new HighlightBuilder().field("*").requireFieldMatch(false);; // hiBuilder.preTags("<span style=/"color:red/">"); // hiBuilder.postTags("</span>"); //搜索title和orperator和detail //QueryStringQueryBuilder queryBuilder = new QueryStringQueryBuilder(param); hiBuilder.field("titles").field("content"); }else{ queryBuilders = QueryBuilders.matchAllQuery(); } } //查询标题 if("title".equals(type)){ queryBuilders = QueryBuilders.fuzzyQuery("titles", param); hiBuilder.field("titles"); } //查询内容 if("content".equals(type)){ queryBuilders = QueryBuilders.fuzzyQuery("content", param); hiBuilder.field("content"); } hiBuilder.fragmentSize(10000);//高亮内容长度 hiBuilder.requireFieldMatch(false); SearchResponse response = transportClient.prepareSearch(IndexName) .setQuery(queryBuilders) .setFrom((pageNo - 1) * pageSize) .setSize(pageSize) .highlighter(hiBuilder) //高亮字段前缀 .setExplain(true)// 设置是否按查询匹配度排序 .execute().actionGet(); SearchHits hits = response.getHits(); int total=(int) hits.getTotalHits(); page.setTotalRecord(total); //总记录数 int totalPage = total/pageSize; if(total % pageSize != 0){ totalPage += 1; } page.setTotalPage(totalPage);//总页数 for (SearchHit searchHit : hits) { Map source = searchHit.getSource(); CsdnBlog entity = (CsdnBlog) JSONObject .toBean(JSONObject.fromObject(source) , CsdnBlog.class); if(!"".equals(type)&&type!=null){ String json=searchHit.getSourceAsString(); CsdnBlog csdnblog=mapper.readValue(json,CsdnBlog.class); //获取高亮域 Map<String,HighlightField> result=searchHit.getHighlightFields(); //查询标题 if("title".equals(type)){ //从高亮域中取得指定域 HighlightField nameField=result.get("titles"); //取得定于的高亮标签 Text[] nameTexts=nameField.getFragments(); //为name串值增加自定义的高亮标签 String titles=""; for(Text text:nameTexts){ titles+=text; } //将追加了高亮标签的串值重新填充到对应的对象 entity.setTitles(titles); } //查询内容 if("content".equals(type)){ //从高亮域中取得指定域 HighlightField nameField=result.get("content"); //取得定于的高亮标签 Text[] contentsTexts=nameField.getFragments(); //为name串值增加自定义的高亮标签 String contents=""; for(Text text:contentsTexts){ contents+=text; } //将追加了高亮标签的串值重新填充到对应的对象 entity.setContent(contents); } //查询所有 if("All".equals(type)){ //从高亮域中取得指定域 HighlightField titlesField=result.get("titles"); if(titlesField!=null&&!"".equals(titlesField)){ //取得定于的高亮标签 Text[] nameTexts=titlesField.getFragments(); //为name串值增加自定义的高亮标签 String titles=""; for(Text text:nameTexts){ titles+=text; } entity.setTitles(titles); } //从高亮域中取得指定域 HighlightField contentField=result.get("content"); if(!"".equals(contentField)&&contentField!=null){ //取得定于的高亮标签 Text[] contentsTexts=contentField.getFragments(); //为name串值增加自定义的高亮标签 String contents=""; for(Text text:contentsTexts){ contents+=text; } entity.setContent(contents); } } } page.getSimpleResult().add(entity); } long end = System.currentTimeMillis(); SearchResponse responses = transportClient.prepareSearch(IndexName) .setQuery(QueryBuilders.matchAllQuery()) .execute().actionGet(); SearchHits hi = responses.getHits(); int totals=(int) hi.getTotalHits(); page.setMessage("在" + totals + "条记录中,搜索("+param+"),共用时间 -->> " + (end - start) + " 毫秒"); System.out.println("在" + totals + "条记录中,搜索"+param+",共用时间 -->> " + (end - start) + " 毫秒"); return page; } }
所有的数据都是用webmagic爬虫进行爬取得,然后使用Logstash-input-jdbc同步数据库中的数据到ES,具体可参考我以前的文章。
完整项目: http://download.csdn.net/download/u011781521/9969651
Github地址: https://github.com/fendo8888/Spring_Elasticsearch5.5.1