【发布时间】:2020-08-03 22:47:27
【问题描述】:
我将 UserAdAccountId 类定义为嵌入式 id 类。使用这个 id 类,我定义了类 UserAdAccount 并为复合主键使用了双向字符串字段桥。然后,我尝试对实体类 AdAccount 进行休眠搜索,但遇到了这个异常:Unable to find field userAdAccounts.id.userId in AdAccount。
如您所见,我将“userAdAccounts.id.userId”作为字段路径传递给 onField(),因为 userAdAccounts 是一组 UserAdAccount。 UserAdAccount 的 id 是 UserAdAccountId 类型,它的字段包括 userId 和 adAccountId。我使用@IndexedEmbedded(includeEmbeddedObjectId = true) 来确保这个UserAdAccountId 类型的id 包含在索引中。
我的问题是为什么我仍然看到这个不正确的字段路径错误?
@Indexed
@Embeddable
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(of = {"userId", "adAccountId"})
@ToString
public class UserAdAccountId implements Serializable {
@Column(name = "USER_ID")
@GenericGenerator( name = "native", strategy = "native")
@Field
private Long userId;
@Column(name = "AD_ACCOUNT_ID")
@GenericGenerator( name = "native", strategy = "native")
@Field
private Long adAccountId;
}
@Entity (name = "JHI_USER_AD_ACCOUNT")
@Indexed
@Getter
@Setter
public class UserAdAccount implements SearchableEntity, Serializable {
@EmbeddedId
@DocumentId
@FieldBridge(impl = UserAdAccoutPrimaryKeyBridge.class)
@IndexedEmbedded(includePaths = {"userId"})
private UserAdAccountId id;
@ManyToOne
@JoinColumn(name = "USER_ID", referencedColumnName = "ID", updatable = false, insertable = false)
private User user;
@ManyToOne
@JoinColumn(name = "AD_ACCOUNT_ID", referencedColumnName = "ID", updatable = false, insertable = false)
private AdAccount adAccount;
}
@Entity
@Indexed
@Table(name = "AD_ACCOUNT")
@Getter
@Setter
@ToString
public class AdAccount implements SearchableEntity, Serializable {
@Id
@DocumentId
@SortableField
@Column(name = "ID")
@GeneratedValue(strategy = GenerationType.AUTO, generator="native")
@GenericGenerator( name = "native", strategy = "native")
private Long id;
@IndexedEmbedded(includeEmbeddedObjectId = true)
@OneToMany(mappedBy = "adAccount", fetch = FetchType.LAZY)
private Set<UserAdAccount> userAdAccounts = new HashSet<>();
}
我实现的休眠搜索逻辑:
if(this.searchRequest.getExactMatchFilters().containsKey("userId")) {
Set<String> userIds = this.searchRequest.getExactMatchFilters().get("userId");
BooleanJunction<BooleanJunction> combined = queryBuilder.bool();
combined.minimumShouldMatchNumber(1);
for(String userId : userIds) {
combined.should(queryBuilder.keyword().onField("userAdAccounts.id.userId").matching(userId).createQuery());
}
filters.add(combined.createQuery());
}
更新:关于双向字段桥的动态映射错误。我在官方文档上找到了这个:我在官方文档上找到了这个:
当您的 MetadataProvidingFieldBridge 注册一个名称为现有字段名称的字段时,附加一个点和另一个字符串,例如 name + ".mySubField",Hibernate Search 会将其转换为 JSON 中具有属性 mySubField 的对象文档发送到 Elasticsearch。
因此,子字段只能有一个 OBJECT 类型的父字段:显然,Elasticsearch 会拒绝带有 mySubField 属性的 String 或 Integer。所以每次注册一个名为 foo.bar 的字段时,它的父字段 foo 必须注册为 OBJECT 类型,如下例所示。不这样做会导致 Hibernate Search 生成 Elasticsearch 架构时出错。
所以就我而言,我做了以下事情。我可能应该使用 Object 类型注册 id 并将 USER_ID_SUFFIX 更改为 .userId 和 AD_ACCOUNT_ID_SUFFIX 到 .adaccountId?
private static final String USER_ID_SUFFIX = "_userId";
private static final String AD_ACCOUNT_ID_SUFFIX = "_adaccountId";
@Override
public void configureFieldMetadata(String id, FieldMetadataBuilder builder) {
builder.field(id + USER_ID_SUFFIX, FieldType.LONG)
.field(id + AD_ACCOUNT_ID_SUFFIX, FieldType.LONG);
}
【问题讨论】:
标签: hibernate-search