【问题标题】:Implement "random" sort in hibernate search elasticsearch在休眠搜索弹性搜索中实现“随机”排序
【发布时间】:2019-07-13 21:56:55
【问题描述】:

我想使用休眠搜索弹性搜索库实现某种“随机”排序。我正在做的事情如下:

实现 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;
  }
}

实现 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"
      }
    }
  ]

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

【问题讨论】:

  • 离题:生成随机数进行比较是个坏主意。该算法可能依赖于一些比较属性,包括相同值的恒定结果和传递性,当它们不满足时,可能会发生任意坏事。 IIRC,C++ 在这种情况下崩溃。

标签: java elasticsearch hibernate-search


【解决方案1】:

我无法使用 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();

【讨论】:

    【解决方案2】:

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

    简单地说,只要您使用 Lucene 接口的自定义实现,您就可以确定它不适用于 Elasticsearch 集成。所以你的RandomOrderFieldComparator 是行不通的。

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

    编辑:我的其余答案是错误的。我忘记了原生排序功能,真丢脸。见other answer

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 2015-07-25
        • 1970-01-01
        • 2021-11-12
        • 1970-01-01
        • 1970-01-01
        • 2019-11-21
        • 2012-04-05
        • 2019-01-26
        • 2015-08-08
        相关资源
        最近更新 更多