如何解决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 在字符串类型上提供的所有功能都将可用。但是当然,范围谓词或排序之类的东西会导致数值的奇怪结果(2
在 10
之前,但 "2"
在 之后 {{1} }).
像这样:
"10"
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。