Reputation: 677
I have class UserAdAccountId defined as an embedded id class. Using this id class, I defined class UserAdAccount and used a two way string field bridge for the composite primary key. Then, I tried to do a hibernate search on the Entity class AdAccount, but ran into this exception: Unable to find field userAdAccounts.id.userId in AdAccount.
As you can see, I passed "userAdAccounts.id.userId" as the field path to onField() because userAdAccounts is a set of UserAdAccount. UserAdAccount's id is of type UserAdAccountId, which has both userId and adAccountId as its fields. I used @IndexedEmbedded(includeEmbeddedObjectId = true) to ensure that this id of type UserAdAccountId is included in indexing.
My question is that why I am still seeing this incorrect field path error?
@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<>();
}
The hibernate search logic I implemented:
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());
}
Update: About the dynamic mapping error with the two way field bridge. I found this on the official documentation: I found this on the official documentation:
When your MetadataProvidingFieldBridge registers a field whose name is the name of an existing field, with a dot and another string appended, like name + ".mySubField", Hibernate Search will translate it as an object with a property mySubField in the JSON document sent to Elasticsearch.
As a result, sub-fields can only have a parent field with the OBJECT type: obviously, Elasticsearch would reject a String or an Integer with mySubField property. So every time a field named foo.bar is registered, its parent field foo must be registered with the OBJECT type, as in the following example. Not doing so will result in errors when Hibernate Search generates the Elasticsearch schema.
So in my case, I did the following. I should probably register id with Object type and also change USER_ID_SUFFIX to be .userId and AD_ACCOUNT_ID_SUFFIX to .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);
}
Upvotes: 1
Views: 1633
Reputation: 9977
You simply did not map field userAdAccounts.id.userId
. You mapped field userAdAccounts.id
, and that's about it. Hibernate Search will only ever add to AdAccount
documents a field named userAdAccounts.id
of type String
. Hibernate Search, as a rule, does not add fields that you didn't ask it to add.
If you also want to add a separate field for the userId
:
TwoWayFieldBridge
implementation that I mentioned in my answer to your other question@IndexedEmbedded
to UserAdAccount.id
and @Field
to UserAdAccountId.userId
.Upvotes: 1