寄生虫网站排名代做,网络工程专业毕业设计,摄影网站的实验设计方案,python做网站用什么软件前面几篇文章详细讲解了 ElasticSearch 的搭建以及使用 SpringDataElasticSearch 来完成搜索查询#xff0c;但是搜索一般都会有搜索关键字高亮的功能#xff0c;今天我们把它给加上。系列文章环境依赖本文以及后续 es 系列文章都基于 5.5.3 这个版本的 elasticsearch #…前面几篇文章详细讲解了 ElasticSearch 的搭建以及使用 SpringDataElasticSearch 来完成搜索查询但是搜索一般都会有搜索关键字高亮的功能今天我们把它给加上。系列文章环境依赖本文以及后续 es 系列文章都基于 5.5.3 这个版本的 elasticsearch 这个版本比较稳定可以用于生产环境。SpringDataElasticSearch 的基本使用可以看我的上一篇文章 和我一起打造个简单搜索之SpringDataElasticSearch入门本文就不再赘述。高亮关键字实现前文查询是通过写一个接口来继承 ElasticsearchRepository 来实现的但是如果要实现高亮我们就不能这样做了我们需要使用到 ElasticsearchTemplate来完成。查看这个类的源码public class ElasticsearchTemplate implements ElasticsearchOperations, ApplicationContextAware {...}可以看到ElasticsearchTemplate 实现了接口 ApplicationContextAware所以这个类是被 Spring 管理的可以在类里面直接注入使用。代码如下:Slf4jComponentpublic class HighlightBookRepositoryTest extends EsSearchApplicationTests {Autowiredprivate ElasticsearchTemplate elasticsearchTemplate;Resourceprivate ExtResultMapper extResultMapper;Testpublic void testHighlightQuery() {BookQuery query new BookQuery();query.setQueryString(穿越);// 复合查询BoolQueryBuilder boolQuery QueryBuilders.boolQuery();// 以下为查询条件, 使用 must query 进行查询组合MultiMatchQueryBuilder matchQuery QueryBuilders.multiMatchQuery(query.getQueryString(), name, intro, author);boolQuery.must(matchQuery);PageRequest pageRequest PageRequest.of(query.getPage() - 1, query.getSize());NativeSearchQuery searchQuery new NativeSearchQueryBuilder().withQuery(boolQuery).withHighlightFields(new HighlightBuilder.Field(name).preTags().postTags(),new HighlightBuilder.Field(author).preTags().postTags()).withPageable(pageRequest).build();Page books elasticsearchTemplate.queryForPage(searchQuery, Book.class, extResultMapper);books.forEach(e - log.info({}, e));// 穿越小道人}}注意这里 的Page books elasticsearchTemplate.queryForPage(searchQuery, Book.class, extResultMapper);这里返回的是分页对象。查询方式和上文的差不多只不过是是 Repository 变成了 ElasticsearchTemplate操作方式也大同小异。这里用到了 ExtResultMapper请接着看下文。自定义ResultMapperResultMapper 是用于将 ES 文档转换成 Java 对象的映射类因为 SpringDataElasticSearch 默认的的映射类 DefaultResultMapper 不支持高亮因此我们需要自己定义一个 ResultMapper。复制 DefaultResultMapper 类重命名为 ExtResultMapper对构造方法名称修改为正确的值。新增一个方法用于将高亮的内容赋值给需要转换的 Java 对象内。在 mapResults 方法内调用这个方法。注意这个类可以直接拷贝到你的项目中直接使用我写这么多只是想说明为什么这个类是这样的。import com.fasterxml.jackson.core.JsonEncoding;import com.fasterxml.jackson.core.JsonFactory;import com.fasterxml.jackson.core.JsonGenerator;import org.apache.commons.beanutils.PropertyUtils;import org.elasticsearch.action.get.GetResponse;import org.elasticsearch.action.get.MultiGetItemResponse;import org.elasticsearch.action.get.MultiGetResponse;import org.elasticsearch.action.search.SearchResponse;import org.elasticsearch.common.text.Text;import org.elasticsearch.search.SearchHit;import org.elasticsearch.search.SearchHitField;import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;import org.springframework.data.domain.Pageable;import org.springframework.data.elasticsearch.ElasticsearchException;import org.springframework.data.elasticsearch.annotations.Document;import org.springframework.data.elasticsearch.annotations.ScriptedField;import org.springframework.data.elasticsearch.core.AbstractResultMapper;import org.springframework.data.elasticsearch.core.DefaultEntityMapper;import org.springframework.data.elasticsearch.core.EntityMapper;import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;import org.springframework.data.mapping.context.MappingContext;import org.springframework.stereotype.Component;import org.springframework.util.Assert;import org.springframework.util.StringUtils;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.lang.reflect.InvocationTargetException;import java.nio.charset.Charset;import java.util.*;/*** 类名称ExtResultMapper* 类描述自定义结果映射类* 创建人WeJan* 创建时间2018-09-13 20:47*/Componentpublic class ExtResultMapper extends AbstractResultMapper {private MappingContext extends ElasticsearchPersistentEntity, ElasticsearchPersistentProperty mappingContext;public ExtResultMapper() {super(new DefaultEntityMapper());}public ExtResultMapper(MappingContext extends ElasticsearchPersistentEntity, ElasticsearchPersistentProperty mappingContext) {super(new DefaultEntityMapper());this.mappingContext mappingContext;}public ExtResultMapper(EntityMapper entityMapper) {super(entityMapper);}public ExtResultMapper(MappingContext extends ElasticsearchPersistentEntity, ElasticsearchPersistentProperty mappingContext,EntityMapper entityMapper) {super(entityMapper);this.mappingContext mappingContext;}Overridepublic AggregatedPage mapResults(SearchResponse response, Class clazz, Pageable pageable) {long totalHits response.getHits().totalHits();List results new ArrayList();for (SearchHit hit : response.getHits()) {if (hit ! null) {T result null;if (StringUtils.hasText(hit.sourceAsString())) {result mapEntity(hit.sourceAsString(), clazz);} else {result mapEntity(hit.getFields().values(), clazz);}setPersistentEntityId(result, hit.getId(), clazz);setPersistentEntityVersion(result, hit.getVersion(), clazz);populateScriptFields(result, hit);// 高亮查询populateHighLightedFields(result, hit.getHighlightFields());results.add(result);}}return new AggregatedPageImpl(results, pageable, totalHits, response.getAggregations(), response.getScrollId());}private void populateHighLightedFields(T result, Map highlightFields) {for (HighlightField field : highlightFields.values()) {try {PropertyUtils.setProperty(result, field.getName(), concat(field.fragments()));} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {throw new ElasticsearchException(failed to set highlighted value for field: field.getName() with value: Arrays.toString(field.getFragments()), e);}}}private String concat(Text[] texts) {StringBuffer sb new StringBuffer();for (Text text : texts) {sb.append(text.toString());}return sb.toString();}private void populateScriptFields(T result, SearchHit hit) {if (hit.getFields() ! null !hit.getFields().isEmpty() result ! null) {for (java.lang.reflect.Field field : result.getClass().getDeclaredFields()) {ScriptedField scriptedField field.getAnnotation(ScriptedField.class);if (scriptedField ! null) {String name scriptedField.name().isEmpty() ? field.getName() : scriptedField.name();SearchHitField searchHitField hit.getFields().get(name);if (searchHitField ! null) {field.setAccessible(true);try {field.set(result, searchHitField.getValue());} catch (IllegalArgumentException e) {throw new ElasticsearchException(failed to set scripted field: name with value: searchHitField.getValue(), e);} catch (IllegalAccessException e) {throw new ElasticsearchException(failed to access scripted field: name, e);}}}}}}private T mapEntity(Collection values, Class clazz) {return mapEntity(buildJSONFromFields(values), clazz);}private String buildJSONFromFields(Collection values) {JsonFactory nodeFactory new JsonFactory();try {ByteArrayOutputStream stream new ByteArrayOutputStream();JsonGenerator generator nodeFactory.createGenerator(stream, JsonEncoding.UTF8);generator.writeStartObject();for (SearchHitField value : values) {if (value.getValues().size() 1) {generator.writeArrayFieldStart(value.getName());for (Object val : value.getValues()) {generator.writeObject(val);}generator.writeEndArray();} else {generator.writeObjectField(value.getName(), value.getValue());}}generator.writeEndObject();generator.flush();return new String(stream.toByteArray(), Charset.forName(UTF-8));} catch (IOException e) {return null;}}Overridepublic T mapResult(GetResponse response, Class clazz) {T result mapEntity(response.getSourceAsString(), clazz);if (result ! null) {setPersistentEntityId(result, response.getId(), clazz);setPersistentEntityVersion(result, response.getVersion(), clazz);}return result;}Overridepublic LinkedList mapResults(MultiGetResponse responses, Class clazz) {LinkedList list new LinkedList();for (MultiGetItemResponse response : responses.getResponses()) {if (!response.isFailed() response.getResponse().isExists()) {T result mapEntity(response.getResponse().getSourceAsString(), clazz);setPersistentEntityId(result, response.getResponse().getId(), clazz);setPersistentEntityVersion(result, response.getResponse().getVersion(), clazz);list.add(result);}}return list;}private void setPersistentEntityId(T result, String id, Class clazz) {if (mappingContext ! null clazz.isAnnotationPresent(Document.class)) {ElasticsearchPersistentEntity persistentEntity mappingContext.getRequiredPersistentEntity(clazz);ElasticsearchPersistentProperty idProperty persistentEntity.getIdProperty();// Only deal with String because ES generated Ids are strings !if (idProperty ! null idProperty.getType().isAssignableFrom(String.class)) {persistentEntity.getPropertyAccessor(result).setProperty(idProperty, id);}}}private void setPersistentEntityVersion(T result, long version, Class clazz) {if (mappingContext ! null clazz.isAnnotationPresent(Document.class)) {ElasticsearchPersistentEntity persistentEntity mappingContext.getPersistentEntity(clazz);ElasticsearchPersistentProperty versionProperty persistentEntity.getVersionProperty();// Only deal with Long because ES versions are longs !if (versionProperty ! null versionProperty.getType().isAssignableFrom(Long.class)) {// check that a version was actually returned in the response, -1 would indicate that// a search didn‘t request the version ids in the response, which would be an issueAssert.isTrue(version ! -1, Version in response is -1);persistentEntity.getPropertyAccessor(result).setProperty(versionProperty, version);}}}}注意这里使用到了 PropertyUtils 需要引入一个 Apache 的依赖。commons-beanutilscommons-beanutils1.9.3自定义 ResultMapper 写好之后添加 Component 注解表示为 Spring 的一个组件在类中进行注入使用即可。最后本文示例项目地址https://github.com/Mosiki/SpringDataElasticSearchQuickStartExample有疑问?欢迎来信给我写信