How to provide highlighting with Spring data elasticsearch

穿精又带淫゛_ 提交于 2019-11-29 04:07:51

问题


it seems that SpringData ES don't provide classes to fetch highlights returned by ES. Spring Data can return Lists of Objects but the highlights sections in the Json returned by ES is in a separated part that is not handled by the "ElasticSearchTemplate" class.

Code example :-

QueryBuilder query = QueryBuilders.matchQuery("name","tom"); 
SearchQuery searchQuery =new NativeSearchQueryBuilder().withQuery(query).
                               with HighlightFields(new Field("name")).build();
List<ESDocument> publications = elasticsearchTemplate.queryForList
                                                (searchQuery, ESDocument.class);

I must be wrong, but I can't figure out to do only with SpringDataES. Someone can post an example of how we can get highlights with Spring Data ES ?

Thanks in advance !


回答1:


From the test cases in spring data elasticsearch I've found solution to this :

This can be helpful.

@Test
public void shouldReturnHighlightedFieldsForGivenQueryAndFields() {

    //given
    String documentId = randomNumeric(5);
    String actualMessage = "some test message";
    String highlightedMessage = "some <em>test</em> message";

    SampleEntity sampleEntity = SampleEntity.builder().id(documentId)
            .message(actualMessage)
            .version(System.currentTimeMillis()).build();

    IndexQuery indexQuery = getIndexQuery(sampleEntity);

    elasticsearchTemplate.index(indexQuery);
    elasticsearchTemplate.refresh(SampleEntity.class);

    SearchQuery searchQuery = new NativeSearchQueryBuilder()
            .withQuery(termQuery("message", "test"))
            .withHighlightFields(new HighlightBuilder.Field("message"))
            .build();

    Page<SampleEntity> sampleEntities = elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class, new SearchResultMapper() {
        @Override
        public <T> Page<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
            List<SampleEntity> chunk = new ArrayList<SampleEntity>();
            for (SearchHit searchHit : response.getHits()) {
                if (response.getHits().getHits().length <= 0) {
                    return null;
                }
                SampleEntity user = new SampleEntity();
                user.setId(searchHit.getId());
                user.setMessage((String) searchHit.getSource().get("message"));
                user.setHighlightedMessage(searchHit.getHighlightFields().get("message").fragments()[0].toString());
                chunk.add(user);
            }
            if (chunk.size() > 0) {
                return new PageImpl<T>((List<T>) chunk);
            }
            return null;
        }
    });

    assertThat(sampleEntities.getContent().get(0).getHighlightedMessage(), is(highlightedMessage));
}



回答2:


Actually, you could do the following, with a custom ResultExtractor:

QueryBuilder query = QueryBuilders.matchQuery("name", "tom"); 
SearchQuery searchQuery = new NativeSearchQueryBuilder()
                           .withQuery(query)
                           .withHighlightFields(new Field("name")).build();
return elasticsearchTemplate.query(searchQuery.build(), new CustomResultExtractor());

And then

public class CustomResultExtractor implements ResultsExtractor<List<MyClass>> {

private final DefaultEntityMapper defaultEntityMapper;

public CustomResultExtractor() {
    defaultEntityMapper = new DefaultEntityMapper();
}


@Override
public List<MyClass> extract(SearchResponse response) {
    return StreamSupport.stream(response.getHits().spliterator(), false) 
        .map(this::searchHitToMyClass) 
        .collect(Collectors.toList());
}

private MyClass searchHitToMyClass(SearchHit searchHit) {
    MyElasticSearchObject myObject;
    try {
        myObject = defaultEntityMapper.mapToObject(searchHit.getSourceAsString(), MyElasticSearchObject.class);
    } catch (IOException e) {
        throw new ElasticsearchException("failed to map source [ " + searchHit.getSourceAsString() + "] to class " + MyElasticSearchObject.class.getSimpleName(), e);
    }
    List<String> highlights = searchHit.getHighlightFields().values()
        .stream() 
        .flatMap(highlightField -> Arrays.stream(highlightField.fragments())) 
        .map(Text::string) 
        .collect(Collectors.toList());
    // Or whatever you want to do with the highlights
    return new MyClass(myObject, highlights);
}}

Note that I used a list but you could use any other iterable data structure. Also, you could do something else with the highlights. Here I'm simply listing them.



来源:https://stackoverflow.com/questions/37049764/how-to-provide-highlighting-with-spring-data-elasticsearch

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!