java - Spring-data-elasticsearch 元数据_score

标签 java spring-data spring-data-elasticsearch

从 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/

相关文章:

java - 在属性文件中的 elasticsearch 中指定索引名称和索引类型

java - 无法使用 eclipse link 和 oracle db 生成表 - IllegalBlockSizeException

java - 带有任何字段到 POJO 的 Json 模式

java - 找不到类型类 java.lang.String 的 PersistentEntity

java - Spring 数据休息 : Foreign key is update with null after post call in one to many relationship

java - 如何在 Spring 中将 ElasticSearch 模型字段标记为 KeyWord 类型?

java - 实现状态模式时将键绑定(bind)应用于状态转换

java.lang.VerifyError : main() threw exception :Incompatible argument to function

java - Hibernate/Spring Data 上的级联删除

java - spring elasticsearch:如何将Map另存为索引中的字符串?