【问题标题】:Can a Hibernate Search FieldBridge configure facets for dynamic fields?Hibernate Search FieldBridge 可以为动态字段配置构面吗?
【发布时间】:2020-03-14 07:27:06
【问题描述】:

使用带有编程 API(无注释)的 Hibernate Search 5.11.3,有没有办法对添加到类或字段桥中的动态字段进行分面?使用 MetadataProvidingFieldBridge 时,我在 FieldMetadataBuilder 中看不到任何“方面”配置。

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

我正在尝试做一个基本的属性方面/过滤器,其中我有一个通用的属性表,其中包含与产品关联的 id/name 和属性值。由于各种原因,我正在使用编程 API,尤其是对于我无法使用 @Facet 注释的属性。所以对于一个产品,我在 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 request 'TAG_56' 尝试在字段 'tag-56' 上设置 facet,该字段要么不存在,要么未配置为 facet(通过 @Facet)。检查您的配置。

我还尝试了这篇文章中解决方案的自定义配置解决方案: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)

【问题讨论】:

    标签: java hibernate lucene hibernate-search


    【解决方案1】:

    简答:Hibernate Search 还不允许这样做……

    长答案:

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

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

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


    关于没有动态字段的工作方式的原始消息(过时):

    也就是说,如果您在启动时知道标签列表,能够将它们全部列出,并且确定在您的应用程序启动时它们不会改变,您可以预先声明这些字段并在它们上使用 faceting .但是,如果您在启动时不知道标签列表,那么(目前)这一切都是不可能的。

    在将动态字段添加到 Hibernate Search 6 之前,唯一的解决方案是使用 Hibernate Search 5 并自己重新实现 faceting。正如您所料,这将是复杂的,您必须亲自动手使用 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 中有一个如何执行分面的示例。

    【讨论】:

    • 感谢您的详细解答!一旦有动态字段,Hibernate Search 6 听起来很有希望。与此同时,我将玩弄你概述的自我刻面,看看我能否让它发挥作用。我也在尝试另一种解决方案,我只需将整个 tagValues 列表索引/分面作为单个字段(而不是每个属性名称的字段)。然后我可以在得到结果后对它们进行适当的分组。这有一些缺点,但它最终可能会足够好并且开箱即用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-15
    • 1970-01-01
    • 1970-01-01
    • 2019-11-27
    相关资源
    最近更新 更多