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