微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Hibernate Search JsonB 索引

如何解决Hibernate Search JsonB 索引

我正在努力使用 Hibernate Search 6.0.2 将 jsonB 列索引到 Elasicsearch 后端

这是我的实体:

@Data
@NoArgsConstructor
@Entity
@Table(name = "examples")
public class Example {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private UUID id;

    @NotNull
    @Column(name = "fields")
    @Type(type = "jsonb")
    private Map<String,Object> fields;
}

这是我用于 Hibernate Search 的 elasticsearch 后端的编程映射:

@Configuration
@requiredArgsConstructor
public class ElasticsearchMappingConfig implements HibernateOrmSearchMappingConfigurer {

    private final JsonPropertyBinder jsonPropertyBinder;

    @Override
    public void configure(HibernateOrmMappingConfigurationContext context) {
        var mapping = context.programmaticMapping();
        var exampleMapping = mapping.type(Example.class);
        exampleMapping.indexed();
        exampleMapping.property("fields").binder(jsonPropertyBinder);
    }
}

我的自定义属性绑定器实现基于 Hibernate Search 6.0.2 documentation

@Component
public class JsonPropertyBinder implements PropertyBinder {

    @Override
    public void bind(PropertyBindingContext context) {
        context.dependencies().useRootOnly();
        var schemaElement = context.indexSchemaElement();
        var userMetadatafield = schemaElement.objectField("Metadata");
        context.bridge(Map.class,new Bridge(userMetadatafield.toReference()));
    }

    @requiredArgsConstructor
    private static class Bridge implements PropertyBridge<Map> {

        private final IndexObjectFieldReference fieldReference;

        @Override
        public void write(DocumentElement target,Map bridgedElement,PropertyBridgeWriteContext context) {
            var map = target.addobject(fieldReference);
            ((Map<String,Object>) bridgedElement).forEach(map::addValue);
        }
    }

}

我知道文档为 Map 中的对象定义了多个模板(如 MultiTypeUserMetadataBinder 示例),但我真的不知道里面可以包含什么。我所知道的是,它是一个有效的 json,我的目标是将它作为“字段”下的有效 json 结构放入 Elasticsearch:{...}

就我而言,jsonB 列可能包含如下内容

    {
        "testString": "298","testNumber": 123,"testBoolean": true,"testNull": null,"testArray": [
            5,4,3
        ],"testObject": {
            "testString": "298","testArray": [
                5,3
            ]
        }

但它抛出异常:

org.hibernate.search.util.common.SearchException: HSEARCH400609: UnkNown field 'Metadata.testNumber'.

我还在 Spring 应用程序中将 dynamic_mapping 设置为 true:

...
spring.jpa.properties.hibernate.search.backend.hosts=127.0.0.3:9200
spring.jpa.properties.hibernate.search.backend.dynamic_mapping=true
...

我该如何解决这个问题的任何其他想法?或者我在某个地方犯了错误

解决方法

我知道文档为 Map 中的对象定义了多个模板(如 MultiTypeUserMetadataBinder 示例),但我真的不知道里面可以包含什么。我所知道的是,它是一个有效的 json,我的目标是将它作为“字段”下的有效 json 结构放入 Elasticsearch:{...}

如果您不知道每个字段的类型是什么,Hibernate Search 将无济于事。如果你真的想把它塞进你的索引中,我建议声明一个 native field 并按原样推送 JSON。但是,您将无法轻松地将谓词应用于元数据字段,除非使用 native JSON

像这样:

@Component
public class JsonPropertyBinder implements PropertyBinder {

    @Override
    public void bind(PropertyBindingContext context) {
        context.dependencies().useRootOnly();
        var schemaElement = context.indexSchemaElement();

        // CHANGE THIS
        IndexFieldReference<JsonElement> userMetadataField = schemaElement.field( 
                "metadata",f -> f.extension(ElasticsearchExtension.get())
                        .asNative().mapping("{\"type\": \"object\",\"dynamic\":true}");
        )
                .toReference();

        context.bridge(Map.class,new Bridge(userMetadataField));
    }

    @RequiredArgsConstructor
    private static class Bridge implements PropertyBridge<Map> {
        private static final Gson GSON = new Gson();

        private final IndexFieldReference<JsonElement> fieldReference;

        @Override
        public void write(DocumentElement target,Map bridgedElement,PropertyBridgeWriteContext context) {
            // CHANGE THIS
            target.addValue(fieldReference,GSON.toJsonTree(bridgedElement));
        }
    }

}

或者,您可以将所有字段声明为字符串。然后 Hibernate Search 在字符串类型上提供的所有功能都将可用。但是当然,范围谓词或排序之类的东西会导致数值的奇怪结果(210 之前,但 "2"之后 {{1} }).

像这样:

"10"

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。