在休眠搜索Elasticsearch中实施“随机”排序

问题描述 投票:0回答:3

我想使用休眠搜索Elasticsearch库实现某种“随机”排序。我在做什么如下:

实现FieldComparator:

public class RandomOrderFieldComparator extends FieldComparator<Integer>  {

  private final Random randomGenerator = new Random();

  @Override
  public int compare(int slot1, int slot2) {
    return randomGenerator.nextInt();
  }

  @Override
  public void setTopValue(Integer value) {
    //not needed as the purpose is to generate random integers w
  }

  @Override
  public Integer value(int slot) {
    return randomGenerator.nextInt();
  }

  @Override
  public LeafFieldComparator getLeafComparator(LeafReaderContext context) throws IOException {
    return null;
  }
}

Implement FieldComparatorSource

public class SampleFieldComparatorSource extends FieldComparatorSource {

  @Override
  public FieldComparator<?> newComparator(String fieldname, int numHits, int sortPos, boolean reversed) throws IOException {
    return new RandomOrderFieldComparator();
  }
}

最后创建一个提供FieldComparatorSource的自定义SortField:

queryBuilder
        .sort()
        .byNative(
            new SortField(
                "id",
                new SampleFieldComparatorSource()
            )
        );

问题是它仍然仅使用'id'字段上的常规排序来生成查询,并且从未命中比较器:

"sort": [
    {
      "id": {
        "order": "asc"
      }
    }
  ]

我在做什么错,使用休眠搜索库实现“随机”排序的最佳方法是什么?

java elasticsearch hibernate-search
3个回答
1
投票

实际上,我找到了一种通过直接通过JSON并使用无痛脚本进行休眠搜索的方法:

queryBuilder.sort()
          .byNative("_script", "{"
                                  + "\"type\" : \"number\","
                                  + "\"script\" : {"
                                  + "   \"lang\": \"painless\","
                                  + "   \"source\": \"new Random().nextInt()\""
                                  + "},"
                                  + "\"order\" : \"asc\""
                                + "}");

1
投票

Elasticsearch集成通过将Lucene对象转换为JSON并将其发送到Elasticsearch集群来工作。它适用于简单的事情,例如按字段值排序,术语查询等,但绝对不能转换您自己实现的Java对象。

简而言之,一旦您使用Lucene接口的自定义实现,就可以确定它不适用于Elasticsearch集成。因此,您的RandomOrderFieldComparator无效。

[如果您需要执行Hibernate Search无法通过其API公开的高级内容,例如这种随机排序,则您必须自己编写发送给Elasticsearch的JSON。 Stackoverflow为该问题提供了various solutions

编辑:我其余的答案是错误的。我忘记了本机排序功能,可惜了。参见other answer


0
投票

我无法使用Hristo Angelov的答案来进行分页工作。我曾尝试使用new Random(long).nextInt(),但无论种子值如何,它都始终生成相同的顺序。按照link in yrodiere's answer的指示,我找到了这个解决方案,该解决方案完美无缺。

String fieldName = "id"; //replace with your search field
String seed = "hello world"; //generate a random string that persists across pages of the same search
sort = qb.sort()
         .byNative("_script", 
                   "{"
                 +    "\"script\" : \"(doc['" + fieldName + "'].value + '" + seed + "').hashCode()\","
                 +    "\"type\" : \"number\"," 
                 +    "\"order\" : \"asc\"" 
                 + "}")
         .createSort();
© www.soinside.com 2019 - 2024. All rights reserved.