【问题标题】:Hibernate search on embedded composite primary key嵌入式复合主键上的休眠搜索
【发布时间】: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


    【解决方案1】:

    您只是没有映射字段userAdAccounts.id.userId。您映射了字段userAdAccounts.id,仅此而已。 Hibernate Search 只会在AdAccount 文档中添加一个名为userAdAccounts.id 类型为String 的字段。 Hibernate Search 通常不会添加您没有要求它添加的字段。

    如果您还想为 userId 添加单独的字段:

    • 要么使用我在answer to your other question 中提到的TwoWayFieldBridge 实现
    • 或者@IndexedEmbedded添加到UserAdAccount.id,将@Field添加到UserAdAccountId.userId

    【讨论】:

    • 我明白了。我已经尝试了你的两个建议:使用@IndexedEmbedded 注释的第二个有效:) 但是对于第一个建议,我得到严格的映射不允许在实体 AdAccount 中动态引入字段 [userAdAccounts.id]。这意味着我需要启用动态映射才能让这个更复杂的 TwoWayFieldBridge 正常工作?
    • @Lyn 这可能意味着您的字段未在架构中正确注册;我猜你的 configureFieldMetadata 实现不使用适当的字段名称,出于某种原因?无论如何,如果它适用于@IndexedEmbedded,最好坚持下去。无论如何,这将是 Hibernate Search 6 中唯一的解决方案(或者至少是最简单的)。
    • 为了回答您的问题,您看到的错误来自 Elasticsearch。 Hibernate Search 5 不支持 Elasticsearch 的动态映射;仅休眠搜索 6 does。但是在您的情况下不需要动态映射。
    • 感谢您的回答。我从官方休眠搜索文档中找到了一些与我得到的动态映射错误相关的内容。我更新了我的问题,因为它不允许我在评论中添加那么多字。
    • 您的解决方案是正确的。没有什么可做的了!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多