刚开始接触elasticsearch的时候就对它的高亮显示比较感兴趣,直接使用es提供的api实现高亮的时候很方便,可以springdata整合es之后,一直没有找到如何实现高亮,网上也查询不到类似的文章。经过一段时间的学习研究,终于知道了如何实现。
话不多说直接开撸!
1、建工程导入依赖。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.huangliwei.elasticsearch</groupId>
<artifactId>elasticsearch_test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 集中定义依赖版本号 -->
<properties>
<spring.version>4.2.4.RELEASE</spring.version>
</properties>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
</dependency>
<!-- elasticsearch -->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>2.4.0</version>
</dependency>
<!-- springdata整合elasticsearch -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>
<!-- 日志相关 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
</dependencies>
<build>
<pluginManagement><!--锁定编译环境,防止update之后恢复成jdk1.5-->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
2、配置文件,springdata整合es提供elasticsearchTemplate,注意如果要使用es标签需要引入elasticsearch的名称空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/data/elasticsearch http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd">
<!-- 配置es包扫描 -->
<elasticsearch:repositories base-package="com.huangliwei.elasticsearch.dao" />
<!-- 配置service包扫描 -->
<context:component-scan base-package="com.huangliwei.elasticsearch.service" />
<!-- 配置elasticsearch连接 -->
<elasticsearch:transport-client id="client"
cluster-nodes="127.0.0.1:9300" />
<!-- springdata整合elasticsearch提供template -->
<bean id="elasticsearchTemplate"
class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate">
<constructor-arg name="client" ref="client"></constructor-arg>
</bean>
</beans>
3、实体类属性,实体用于封装唐诗,title为诗歌名称和作者,content为诗歌内容,存入分词和搜索分词都是用ik分词器
4、准备数据,已经向es中插入100首诗歌
5、为了方便贴代码,直接将所有代码写到了测试用例里面
package com.huangliwei.elasticsearch.springesdemo;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.highlight.HighlightBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.huangliwei.elasticsearch.entity.Poem;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class SpringDataEsTest {
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Test
public void highLightQueryTest() {
String field = "content";
String searchMessage = "三";
List<Poem> poems = highLigthQuery(field, searchMessage);
System.out.println(poems);
}
public List<Poem> highLigthQuery(String field, String searchMessage) {
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.termQuery(field, searchMessage))
.withHighlightFields(new HighlightBuilder.Field(field)).build();
Page<Poem> page = elasticsearchTemplate.queryForPage(searchQuery, Poem.class, new SearchResultMapper() {
@Override
public <T> Page<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
ArrayList<Poem> poems = new ArrayList<Poem>();
SearchHits hits = response.getHits();
for (SearchHit searchHit : hits) {
if (hits.getHits().length <= 0) {
return null;
}
Poem poem = new Poem();
String highLightMessage = searchHit.getHighlightFields().get(field).fragments()[0].toString();
poem.setId(Integer.parseInt(searchHit.getId()));
poem.setTitle(String.valueOf(searchHit.getSource().get("title")));
poem.setContent(String.valueOf(searchHit.getSource().get("content")));
// 反射调用set方法将高亮内容设置进去
try {
String setMethodName = parSetName(field);
Class<? extends Poem> poemClazz = poem.getClass();
Method setMethod = poemClazz.getMethod(setMethodName, String.class);
setMethod.invoke(poem, highLightMessage);
} catch (Exception e) {
e.printStackTrace();
}
poems.add(poem);
}
if (poems.size() > 0) {
return new PageImpl<T>((List<T>) poems);
}
return null;
}
});
List<Poem> poems = page.getContent();
return poems;
}
/**
* 拼接在某属性的 set方法
*
* @param fieldName
* @return String
*/
private static String parSetName(String fieldName) {
if (null == fieldName || "".equals(fieldName)) {
return null;
}
int startIndex = 0;
if (fieldName.charAt(0) == '_')
startIndex = 1;
return "set" + fieldName.substring(startIndex, startIndex + 1).toUpperCase()
+ fieldName.substring(startIndex + 1);
}
}
6、测试结果
(1)要搜索李白的诗歌,搜索field为title,搜索searchMessage为“李白“。结果字符串"李白"都已经被加上<em>标签。
(2)要搜索诗歌内容包含数字"三"的诗歌,field为content,searchMessage为"三"。结果字符串"三"也都已经被加上<em>标签。
如果要同时将多个字段加上高亮,则只需要将field传入的单个field改成传入field数组,反射调用set方法时同时调用其他字段的set方法。
第一次写博客,写得不好大家见谅。