我在使用休眠搜索进行实体搜索时遇到问题。 就我而言,我需要搜索:
这是我的实体:
@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,我不能使用布尔运算符,例如“AND using +”
List<TestEntity> hits = searchSession.search( TestEntity.class )
.where( f -> f.match().field( "data" )
.matching( "ObjectKey ObjectData" ).fuzzy())
.fetchHits( 20 );
如何使用键值在内部 json 中搜索?
答案 0 :(得分:0)
如果您想使用 Hibernate Search DSL 进行搜索,您需要让 Hibernate Search 了解您的架构:字段、它们的名称、它们的类型……
通过仅声明一个“数据”字段并将 JSON 直接推送到其中,您可以有效地对 Hibernate Search 隐藏模式。您还依赖 Elasticsearch 在字段类型首次填充到索引中时自动检测它们的能力,这可能会导致意外情况。
当您这样做时,您唯一的搜索解决方案是绕过 Hibernate Search 并转到 write down the JSON of your query yourself。有关 JSON 语法,请参阅 here。就我个人而言,我会避免这种情况,但对每个人来说都是如此。
实际上,更好的解决方案是使用 field templates 干净地声明所有字段。这样 Hibernate Search 就会知道每个字段的类型,你就可以利用 DSL。
对于在单个谓词中定位所有字段,Hibernate Search 尚不支持 (HSEARCH-3926)。您必须:
f.match().fields( "data.SomeKey", "data.SomeOtherKey", "data.SomeThirdKey" )
data
旁边的另一个字段中,例如 data_all
,然后在该字段上进行搜索。copy_to
feature。当然,您还必须声明要复制到的字段。然后,您将在搜索时定位此字段。