从 Spring-Data 查询 Elasticsearch 时,我想获得 _score
如果我们采用以下简单的类:
@Document(indexName = "test", type = "el_test")
public static class ElTest{
private long id;
private String myField;
}
使用 JUnit 测试
@Test
public void testScore() throws Exception {
elasticsearchTemplate.index(new IndexQueryBuilder()
.withIndexName("test")
.withObject(new ElTest("first value"))
.build());
elasticsearchTemplate.index(new IndexQueryBuilder()
.withIndexName("test")
.withObject(new ElTest("second value"))
.build());
elasticsearchTemplate.index(new IndexQueryBuilder()
.withIndexName("test")
.withObject(new ElTest("third"))
.build());
SearchQuery query = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.matchQuery("myField","second value"))
.build();
List<ElTest> els = elasticsearchTemplate.queryForList(query, ElTest.class);
assertEquals(2, els.size());
}
这将在 Elasticsearch 中创建 3 个条目。该查询将检索两个具有不同分数的值。
如果我们直接将请求放入Elasticsearch:
POST /test/_search
{
"query": {
"match" : {
"myField" : {
"query" : "second value",
"type" : "boolean"
}
}
}
}
Elasticsearch 的响应:
{
"took": 15,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 0.8838835,
"hits": [
{
"_index": "test",
"_type": "el_test",
"_id": "AVKmmYCL3xnXT_BGRA3T",
"_score": 0.8838835,
"_source": {
"id": 0,
"myField": "second value"
}
},
{
"_index": "test",
"_type": "el_test",
"_id": "AVKmmYCI3xnXT_BGRA3S",
"_score": 0.028130025,
"_source": {
"id": 0,
"myField": "first value"
}
}
]
}
}
当我取回 ElTest 对象列表时,我无法检索 _score 值(0.8838835 和 0.028130025)。有没有办法获取Spring-data中的值?
我会想象类似的事情
@Document(indexName = "test", type = "el_test")
public static class ElTest{
private long id;
private String myField;
@Score
private double score;
}
其中 Score 是一个注释,指示该字段由 Elasticsearch 填充。
我想要分数的原因是为了对 GUI 中的列表进行排序。
由于从 Elasticsearch 到 gui 的许多 dto 映射,列表在某些地方未排序。因此它是不可靠的。
我当然可以手动添加分数值,但这需要迭代列表。这不太好。
我使用 Spring-data-elasticsearch 版本 1.2.0,因此使用 Elasticsearch 1.4.4
最佳答案
我也在寻找同样的东西。
我发现在 ElasticsearchTemplate 类实例中使用了 DefaultResultMapper :
@Override
public <T> FacetedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
long totalHits = response.getHits().totalHits();
List<T> results = new ArrayList<T>();
for (SearchHit hit : response.getHits()) {
if (hit != null) {
T result = null;
if (!Strings.isNullOrEmpty(hit.sourceAsString())) {
result = mapEntity(hit.sourceAsString(), clazz);
} else {
result = mapEntity(hit.getFields().values(), clazz);
}
setPersistentEntityId(result, hit.getId(), clazz);
results.add(result);
}
}
List<FacetResult> facets = new ArrayList<FacetResult>();
if (response.getFacets() != null) {
for (Facet facet : response.getFacets()) {
FacetResult facetResult = DefaultFacetMapper.parse(facet);
if (facetResult != null) {
facets.add(facetResult);
}
}
}
return new FacetedPageImpl<T>(results, pageable, totalHits, facets);
}
分数存储在 SearchHit 实例中,但在 hit.sourceAsString() 中被忽略...
作为解决方法,我创建了一个简单的界面:
/**
* Object to have score from elastic search
*/
public interface Scoreable {
float getScore();
void setScore(float score);
}
和扩展的DefaultResultMapper:
/**
* Results mapper with score support
*/
public class ScoreResultsMapper extends DefaultResultMapper {
public ScoreResultsMapper(MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext) {
super(mappingContext);
}
@Override
public <T> FacetedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
FacetedPage<T> resultPage = super.mapResults(response, clazz, pageable);
Iterator<T> it = resultPage.getContent().iterator();
for (SearchHit hit : response.getHits()) {
if (hit != null) {
T next = it.next();
if (next instanceof Scoreable) {
((Scoreable) next).setScore(hit.score());
}
}
}
return resultPage;
}
}
这里我只是检查返回的类型是否是 Scoreable 的实例,如果是,我将分数放入其中
现在我可以使用新的映射器配置ElasticsearchTemplate(我正在使用 spring-boot):
@Bean
public ElasticsearchTemplate elasticsearchTemplate() {
MappingElasticsearchConverter converter = new MappingElasticsearchConverter(new SimpleElasticsearchMappingContext());
ScoreResultsMapper mapper = new ScoreResultsMapper(converter.getMappingContext());
return new ElasticsearchTemplate(client(), converter, mapper);
}
当然,我所有带有分数的文档都必须扩展Scorable。 我们可能必须重写 DefaultResultMapper 的一些其他方法才能在其他类型的查询中获得分数支持。
关于java - Spring-data-elasticsearch 元数据_score,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35175319/