繁体   English   中英

使用 hibernate 搜索在 json 字段中搜索

[英]Search in json field using hibernate search

我在使用 hibernate 搜索的实体进行搜索时遇到问题。 就我而言,我需要搜索:

  • 所有领域;
  • 通过 json 字段中的键值

这是我的实体:

@Entity
@Indexed(index = "test")
@Table(name = "test")
@TypeDef(name = "jsonb", typeClass = Jsonb.class)
public class TestEntity {

    @Id
    @Column(name = "id")
    private UUID Id;

   @FullTextField
    @Column(name = "name", nullable = false, length = 50)
    private String name;

    @FullTextField
    @Column(name = "desc")
    private String desc;

    @Column(name = "data")
    @Type(type = "jsonb")
    @ElementCollection
    @PropertyBinding(binder = @PropertyBinderRef(type = JsonPropertyBinderNew.class))
    private Map<String, Object> data;
//constructor
//getters 
//setters
}

实体有一个 JSONB 格式的列。 使用 PropertyBinder 我将它保存在弹性中:

public class JsonPropertyBinder implements PropertyBinder {

    @Override
    public void bind(PropertyBindingContext context) {
        context.dependencies().useRootOnly();

        IndexSchemaElement schemaElement = context.indexSchemaElement();

        IndexFieldType<String> amountFieldType = context.typeFactory()
                .asString().analyzer("english").toIndexFieldType();

        context.bridge(Map.class, new Bridge(
                schemaElement.field("data", amountFieldType).toReference()));
    }

    private static class Bridge implements PropertyBridge<Map> {
        private IndexFieldReference<String> data;

        public Bridge(IndexFieldReference<String> data) {
            this.data = data;
        }

        @Override
        public void write(DocumentElement target, Map bridgedElement, PropertyBridgeWriteContext context) {
            Gson gson = new Gson();
            target.addValue(data, gson.toJson(bridgedElement));
        }
    }

在弹性中它看起来像:

data: {"SomeKey":"SomeKey","StringKey":"Stroka","ObjectKey":"ObjectData"}
desc:Fourth
name: Fourth Test Name

当我尝试按字段搜索时

List<TestEntity> result = searchSession.search(TestEntity.class)
                .where(f -> f.exists().field("data.SomeKey"))
                .fetchHits(20);

我得到了例外:“org.hibernate.search.util.common.SearchException:HSEARCH400504:未知字段'data.SomeKey'”

如果我尝试使用simpleQueryString它可以工作,但我不能使用模糊测试:

SearchResult<TestEntity> search = searchSession.search(TestEntity.class)
            .where(f -> f.simpleQueryString()
                    .fields("data")
                    .matching("ObjectKey + ObjectData")
            ).fetch(20);

如果我尝试使用 Predicate DSL,我不能使用 boolean 运算符,例如“AND using +”

List<TestEntity> hits = searchSession.search( TestEntity.class )
                .where( f -> f.match().field( "data" )
                        .matching( "ObjectKey ObjectData" ).fuzzy())
                .fetchHits( 20 );

我如何使用键值对内部 json 进行搜索?

如果您想使用 Hibernate Search DSL 进行搜索,您需要让 Hibernate Search 了解您的架构:字段、名称、类型、...

通过仅声明一个“数据”字段并将 JSON 直接推入其中,您实际上是从 Hibernate 搜索中隐藏了架构。 您还依赖于 Elasticsearch 在首次将字段类型填充到索引中时自动检测字段类型的能力,这可能会导致严重的意外。

当您这样做时,您唯一的搜索解决方案是绕过 Hibernate 搜索并自己写下查询的 JSON 请参阅此处了解 JSON 语法。 我个人会避免这种情况,但对每个人来说都是他自己的。

确实,更好的解决方案是使用字段模板干净地声明所有字段。 这样 Hibernate 搜索就会知道每个字段的类型,您就可以利用 DSL。


至于针对单个谓词中的所有字段,Hibernate 搜索尚不支持 ( HSEARCH-3926 )。 您必须:

  • 列出谓词中的所有字段,例如f.match().fields( "data.SomeKey", "data.SomeOtherKey", "data.SomeThirdKey" )
  • 或者将 JSON 中每个单个值的数据放在data旁边的另一个字段中,比如data_all ,然后在该字段上进行搜索。
  • 或者更改您的活页夹以声明字段模板,并为这些字段使用本机字段类型以利用 Elasticsearch 的copy_to功能 当然,您还必须声明要复制到的字段。 然后,您将在搜索时定位该字段。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM