如何使用 Spring 数据 elasticsearch 提供高亮显示

How to provide highlighting with Spring data elasticsearch

似乎 SpringData ES 不提供 classes 来获取由 ES 编辑的 return 亮点。 Spring 数据可以 return 对象列表,但 ES 编辑的 Json return 中的高亮部分位于 "ElasticSearchTemplate" 未处理的单独部分class.

代码示例:-

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);

我可能是错的,但我想不出只使用 SpringDataES。有人可以 post 举例说明我们如何使用 Spring Data ES 获得亮点?

提前致谢!

根据 spring data elasticsearch 中的测试用例,我找到了解决方案:

这会有所帮助。

@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));
}

实际上,您可以使用自定义 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());

然后

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);
}}

请注意,我使用了列表,但您可以使用任何其他可迭代数据结构。此外,您还可以对亮点进行其他操作。这里我简单罗列一下。

第一个答案确实有效,但我发现它的返回结果存在一些可分页的问题,显示的总元素错误 toalpages.Arter 我检查了 DefaultResultMapper 实现,返回的语句应该是 return new AggregatedPageImpl((List<T>) chunk, pageable, totalHits, response.getAggregations(), response.getScrollId(), maxScore);,然后它与 paging.wish 合作,我可以帮助你们~

Spring Data Elasticsearch 4.0 现在有 SearchPage 结果类型,如果我们需要 return 突出显示结果,这会让事情变得更容易一些:

这是一个工作示例:

    String query = "(id:123 OR id:456) AND (database:UCLF) AND (services:(sealer?), services:electronic*)"
    
    NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
            .withPageable(pageable)
            .withQuery(queryStringQuery(query))
            .withSourceFilter(sourceFilter)
            .withHighlightFields(new HighlightBuilder.Field("goodsAndServices"))
            .build();
    
    
    SearchHits<Trademark> searchHits = template.search(searchQuery, Trademark.class, IndexCoordinates.of("trademark"));
    SearchPage<Trademark> page = SearchHitSupport.searchPageFor(searchHits, searchQuery.getPageable());
    return (Page<Trademark>) SearchHitSupport.unwrapSearchHits(page);

这将是 json 中 Page 对象的响应:

{
    "content": [
        {
            "id": "123",
            "score": 12.10748,
            "sortValues": [],
            "content": {
                "_id": "1P0XzXIBdRyrchmFplEA",
                "trademarkIdentifier": "abc234",
                "goodsAndServices": null,
                "language": "EN",
                "niceClass": "2",
                "sequence": null,
                "database": "UCLF",
                "taggedResult": null
            },
            "highlightFields": {
                "goodsAndServices": [
                    "VARNISHES, <em>SEALERS</em>, AND NATURAL WOOD FINISHES"
                ]
            }
        }
    ],
    "pageable": {
        "sort": {
            "unsorted": true,
            "sorted": false,
            "empty": true
        },
        "offset": 0,
        "pageNumber": 0,
        "pageSize": 20,
        "unpaged": false,
        "paged": true
    },
    "searchHits": {
        "totalHits": 1,
        "totalHitsRelation": "EQUAL_TO",
        "maxScore": 12.10748,
        "scrollId": null,
        "searchHits": [
            {
                "id": "123",
                "score": 12.10748,
                "sortValues": [],
                "content": {
                    "_id": "1P0XzXIBdRyrchmFplEA",
                    "trademarkIdentifier": "abc234",
                    "goodsAndServices": null,
                    "language": "EN",
                    "niceClass": "2",
                    "sequence": null,
                    "database": "UCLF",
                    "taggedResult": null
                },
                "highlightFields": {
                    "goodsAndServices": [
                        "VARNISHES, <em>SEALERS</em>, AND NATURAL WOOD FINISHES"
                    ]
                }
            }
        ],
        "aggregations": null,
        "empty": false
    },
    "totalPages": 1,
    "totalElements": 1,
    "size": 20,
    "number": 0,
    "numberOfElements": 1,
    "last": true,
    "first": true,
    "sort": {
        "unsorted": true,
        "sorted": false,
        "empty": true
    },
    "empty": false
}