首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Spring-data-elasticsearch元数据_score

Spring-data-elasticsearch元数据_score
EN

Stack Overflow用户
提问于 2016-02-03 11:06:10
回答 1查看 3.8K关注 0票数 3

当从Spring查询Elasticsearch时,我想获得_score

如果我们选择以下简单的课程:

代码语言:javascript
复制
@Document(indexName = "test", type = "el_test")
public static class ElTest{
    private long id;
    private String myField;
}

用JUnit测试

代码语言:javascript
复制
@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中:

代码语言:javascript
复制
POST /test/_search
{
  "query": { 
    "match" : {
      "myField" : {
        "query" : "second value",
         "type" : "boolean"
      }
    }
  }
}

来自Elasticsearch的回应:

代码语言:javascript
复制
{
  "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中获得值吗?

我可以想象一下

代码语言:javascript
复制
@Document(indexName = "test", type = "el_test")
public static class ElTest{
    private long id;
    private String myField;
    @Score
    private double score;
}

其中得分将是一个注释,表示该字段由Elasticsearch填充。

我想要分数的原因是为了对gui中的列表进行排序。

由于从Elasticsearch到gui的许多dto映射,列表在某些地方没有排序。因此,它不可靠。

当然,我可以手工添加一个得分值,但是它需要迭代列表。这不是很好。

我使用Spring Elasticsearch版本1.2.0,因此使用Elasticsearch 1.4.4

EN

回答 1

Stack Overflow用户

发布于 2016-02-25 20:23:48

我在找同样的人。

我发现在ElasticsearchTemplate类中,DefaultResultMapper实例用于它:

代码语言:javascript
复制
@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()中被忽略.

作为解决办法,我创建了一个简单的界面:

代码语言:javascript
复制
/**
 * Object to have score from elastic search
 */
public interface Scoreable {

    float getScore();

    void setScore(float score);
}

和扩展的DefaultResultMapper

代码语言:javascript
复制
/**
 * 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;
    }
}

在这里,我只是检查返回类型是否是得分的实例,如果是的话,我会把分数加进去。

因此,现在我可以使用新的映射器配置ElasticsearchTemplate (我使用的是spring):

代码语言:javascript
复制
@Bean
public ElasticsearchTemplate elasticsearchTemplate() {
    MappingElasticsearchConverter converter = new MappingElasticsearchConverter(new SimpleElasticsearchMappingContext());
    ScoreResultsMapper mapper = new ScoreResultsMapper(converter.getMappingContext());
    return new ElasticsearchTemplate(client(), converter, mapper);
}

当然,我所有有分数的文档都必须扩展可记分。为了在其他类型的查询中获得分数支持,我们可能需要覆盖DefaultResultMapper的其他一些方法。

票数 13
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35175319

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档