Hibernate Search FieldBridge 可以为动态字段配置构面吗?

Can a Hibernate Search FieldBridge configure facets for dynamic fields?

将 Hibernate Search 5.11.3 与程序化 API(无注释)结合使用,有没有办法在 class 或字段桥中添加的动态字段上分面?使用 MetadataProvidingFieldBridge 时,我在 FieldMetadataBuilder 中看不到任何可用的 'facet' 配置。

我在 set() 方法中尝试了 luceneOptions.addSortedDocValuesFieldToDocument() 和 luceneOptions.addFieldToDocument() 的各种组合。这成功更新了索引,但我无法执行分面查询。

我正在尝试做一个基本属性 facet/filter,其中我有一个通用的 table 属性 id/name 和与产品相关的属性值。由于各种原因,我正在使用程序化 API,尤其是对于我无法使用 @Facet 注释的属性。所以对于一个产品,我将这个 class 桥添加到 Product.class:

public class ProductClassTagValuesBridge implements FieldBridge
{
    @Override
    public void set(String name, Object value, Document document, LuceneOptions luceneOptions)
    {
        Product product = (Product) value;

        for (TagValue v : product.getTagValues())
        {
            Tag tag = v.getTag();
            String tagName = "tag-" + tag.getId();
            String tagValue = v.getId().toString();

            // not sure if this line is required? Have tried with and without
            luceneOptions.addFieldToDocument(tagName, tagValue, document);

            luceneOptions.addSortedDocValuesFieldToDocument(tagName, tagValue, document);
        }
    }
}

然后我构建我的(测试)分面请求来搜索 tag-56(我使用 Luke 确认它在索引中):

FacetParameterContext context = queryBuilder.facet()
        .name("tag-56")
        .onField("tag-56")
        .discrete();

FacetingRequest facetingRequest = context.createFacetingRequest();

在 search/FacetManager 中使用时出现错误:

org.hibernate.search.exception.SearchException:HSEARCH000268:Facet 请求 'TAG_56' 尝试在不存在或未配置为分面的字段 'tag-56' 上分面(通过 @Facet)。检查您的配置。

我也试过这个 post 中解决方案的自定义配置解决方案:Hibernate Search: configure Facet for custom FieldBridge

对于自定义字段,我在我的产品上添加了一个字段桥接至 tagValues。出现同样的错误。

mapping.entity(Product.class).indexed()
    .property("tagValues", ElementType.FIELD).field()
        .analyze(Analyze.NO).store(Store.YES)
        .bridge(ProductTagValuesFieldBridge.class)

简答:Hibernate Search 不允许...还没有。

长答案:

Hibernate Search 5 允许动态字段,但不允许在自定义桥中声明的字段上分面。 也就是说,您可以向索引添加不符合预定义架构的任意值,但您不能在这些字段上使用分面。

Hibernate 搜索 6 允许在自定义桥中声明的字段上进行分面(现在称为“聚合”)(只需将它们声明为 .aggregable(Aggregable.YES)),但是 does not allow dynamic fields yet.

编辑: 从 6.0.0.Beta7 开始,通过字段模板支持动态字段。所以我的其余信息不再有用了。 有关字段模板的更多信息,请参阅 this section of the documentation。完全可以在您的桥中声明一个可聚合的动态字段。


关于不使用动态字段的工作方式的原始消息(已过时):

也就是说,如果您知道启动时的标签列表,能够将它们全部列出,并且确定它们在您的应用程序启动时不会改变,您可以预先声明字段并使用分面在他们。但是,如果您不知道启动时的标签列表,none 这是可能的(还)。

在将动态字段添加到 Hibernate Search 6 之前,唯一的解决方案是使用 Hibernate Search 5 并自己重新实现分面。如您所料,这将很复杂,您将不得不亲自动手使用 Lucene。您将必须:

  1. SortedSetDocValuesFacetField 类型的字段添加到自定义桥中的文档。
  2. 确保 Hibernate Search 在您的文档被填充后调用 FacetsConfig.build。一种方法(通过 hack)是在您的实体上声明一个虚拟 @Facet 字段,即使您不使用它也是如此。
  3. 完全忽略 Hibernate Search 的查询功能并从 IndexReader 中自己执行分面。您可以从 Hibernate Search as explained here 获得 IndexReaderorg.hibernate.search.query.engine.impl.QueryHits#updateStringFacets.
  4. 中有一个如何执行分面的示例