How to index composite primary keys in hibernate search

北城以北 提交于 2021-02-11 12:32:27

问题


I have the following class definitions and for class UserAdAccount, it uses both the adAccountId and userId as its composite primary key. I need to use this composite primary key as the document id for indexing.

After reading the Hibernate Search 5.11.5.Final: Reference Guide(This is the version I am using), I found the following: The more powerful TwoWayFieldBridge interface allows you to store more than one field into the index, which can be useful for composite properties, but is more complex to implement.

I am not sure how to proceed using the TwoWayFieldBridge to address my need here. Any help is appreciated!

@Entity (name = "JHI_USER_AD_ACCOUNT")
@Indexed
@IdClass(UserAdAccountId.class)
@Getter
@Setter
public class UserAdAccount implements SearchableEntity, Serializable { 
    //newly added id field with two way string bridge
    @DocumentId
    @Column(name = "ID")
    @FieldBridge(impl = UserAdAccoutPrimaryKeyBridge.class)
    private UserAdAccountId id;

    @Id
    @Column(name = "AD_ACCOUNT_ID")
    @GenericGenerator( name = "native", strategy = "native")
    @Field
    private Long adAccountId;

    @Id
    @Column(name = "USER_ID")
    @GenericGenerator( name = "native", strategy = "native")
    @Field
    private Long userId;

    @ManyToOne
    @JoinColumn(name = "USER_ID", referencedColumnName = "ID", updatable = false, insertable = false)
    @JsonIgnore
    private User user;

    @ManyToOne
    @JoinColumn(name = "AD_ACCOUNT_ID", referencedColumnName = "ID", updatable = false, insertable = false)
    @IndexedEmbedded(includePaths = "name")
    private AdAccount adAccount;
}


@Getter
@Setter
@EqualsAndHashCode(of = {"userId", "adAccountId"})
public class UserAdAccountId implements Serializable {
    private Long userId;
    private Long adAccountId;
}


public class UserAdAccoutPrimaryKeyBridge implements TwoWayStringBridge {

    @Override
    public String objectToString(Object object) {
        UserAdAccountId userAdAccountId = (UserAdAccountId) object;
        StringBuilder buffer = new StringBuilder();
        buffer.append(userAdAccountId.getUserId()).append("-").append(userAdAccountId.getAdAccountId());
        return buffer.toString();
    }

    @Override
    public Object stringToObject(String value) {
        String[] components = value.split("-");
        UserAdAccountId userAdAccountId = new UserAdAccountId();
        userAdAccountId.setUserId(Long.parseLong(components[0]));
        userAdAccountId.setAdAccountId(Long.parseLong(components[1]));
        return userAdAccountId;
    }
}

回答1:


From the documentation:

It is important for the two-way process to be idempotent, i.e.: [...]

  • for TwoWayFieldBridge: for a given document, the object returned by get() must be the same as the one that was originally passed to set().

Also, in order for TwoWayFieldBridge implementations to work correctly when used on a document identifier, the void set(String name, Object value, Document document, LuceneOptions luceneOptions) method must add a field to the document following these conventions:

  • the field name must be the name provided in the name parameter
  • the field value must be encoded as a String
  • the field value must be unique to the given value of the value parameter
  • the field value must match what the objectToString method would return for the given value parameter.

You can find an example implementation for a composite primary key on github:

public class PersonPKBridge implements TwoWayFieldBridge, MetadataProvidingFieldBridge {

    private static final String FIRST_NAME_SUFFIX = "_content.firstName";
    private static final String LAST_NAME_SUFFIX = "_content.lastName";

    @Override
    public void configureFieldMetadata(String name, FieldMetadataBuilder builder) {
        builder.field( name + FIRST_NAME_SUFFIX, FieldType.STRING )
            .field( name + LAST_NAME_SUFFIX, FieldType.STRING );
    }

    @Override
    public Object get(String name, Document document) {
        PersonPK id = new PersonPK();
        IndexableField field = document.getField( name + FIRST_NAME_SUFFIX );
        id.setFirstName( field.stringValue() );
        field = document.getField( name + LAST_NAME_SUFFIX );
        id.setLastName( field.stringValue() );
        return id;
    }

    @Override
    public String objectToString(Object object) {
        PersonPK id = (PersonPK) object;
        StringBuilder sb = new StringBuilder();
        sb.append( id.getFirstName() ).append( " " ).append( id.getLastName() );
        return sb.toString();
    }

    @Override
    public void set(String name, Object value, Document document, LuceneOptions luceneOptions) {
        PersonPK id = (PersonPK) value;

        //store each property in a unique field
        luceneOptions.addFieldToDocument( name + FIRST_NAME_SUFFIX, id.getFirstName(), document );

        luceneOptions.addFieldToDocument( name + LAST_NAME_SUFFIX, id.getLastName(), document );

        //store the unique string representation in the named field
        luceneOptions.addFieldToDocument( name, objectToString( id ), document );
    }

}

Alternatively, if you're certain the components of your ID don't contain a certain string, you will be able to use that string as a separator for the indexed form of your ID, and you'll be able to convert that indexed form back to the original ID. This means you can use the simpler TwoWayStringBridge and rely on concatenation/splitting:

public class PersonPKBridge implements TwoWayStringBridge {

    @Override
    public String objectToString(Object object) {
        PersonPK id = (PersonPK) object;
        StringBuilder sb = new StringBuilder();
        sb.append( id.getFirstName() ).append( " " ).append( id.getLastName() );
        return sb.toString();
    }

    @Override
    public Object stringToObject(String value) {
        String[] components = value.split(" ");
        PersonPK id = new PersonPK();
        id.setFirstName( components[0] );
        id.setLastName( components[1] );
        return id;
    }

}


来源:https://stackoverflow.com/questions/63182446/how-to-index-composite-primary-keys-in-hibernate-search

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!