Hibernate 搜索嵌入式复合主键

Hibernate search on embedded composite primary key

我将 class UserAdAccountId 定义为嵌入式 ID class。使用此 ID class,我定义了 class UserAdAccount 并为复合主键使用了双向字符串字段桥。然后,我尝试对实体 class AdAccount 进行休眠搜索,但 运行 进入此异常:无法在 AdAccount 中找到字段 userAdAccounts.id.userId。

如您所见,我将“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<>();
}

我实现的hibernate搜索逻辑:

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 将 运行 将其列为一个在发送到 Elasticsearch 的 JSON 文档中带有 属性 mySubField 的对象。

因此,子字段只能有 OBJECT 类型的父字段:显然,Elasticsearch 会拒绝带有 mySubField 属性 的字符串或整数。因此每次注册名为 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);
}

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

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

  • 要么使用我在
  • 中提到的 TwoWayFieldBridge 实现
  • @IndexedEmbedded添加到UserAdAccount.id并将@Field添加到UserAdAccountId.userId