Spring Boot Hibernate搜索同步策略与继承

v9tzhpje  于 2022-12-23  发布在  Spring
关注(0)|答案(1)|浏览(145)

我有一个有3个实体的Sping Boot 项目,UserEntity是一个独立的实体,Person是由律师继承的实体。
我将自动索引策略设置为同步,当我将新用户插入数据库时,新用户会立即被选中,但新律师或人员会被索引,但直到我重新启动海量索引器才会出现在结果中。
用户实体:

@Entity
@Accessors(chain = true)
@Getter
@Setter
@Indexed
@SyncAnnotation(convertor = UserConvertor.class, repoClass = UserDetailServiceImplementation.class)
public class UserEntity implements UserDetails {

    @Id
    @Basic
    @Column(name = "id", columnDefinition = "uniqueidentifier")
    @Type(type = "uuid-char")
    private UUID id;

    @Column(name = "user_name", length = 20)
    @Basic
    private String username;

    @Basic
    @Column(name = "email")
    @Email
    private String email;

    @Basic
    @Column(name = "full_name", length = 50, nullable = false, columnDefinition = "nvarchar(50)")
    @NotNull
    @FullTextField(termVector = TermVector.WITH_POSITIONS_OFFSETS)
    private String fullName;

个人实体:

@Entity
@Accessors(chain = true)
@Getter
@Setter
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "person_type", discriminatorType = DiscriminatorType.INTEGER)
@DiscriminatorValue("1")
@Indexed
@SyncAnnotation(convertor = ClientConvertor.class, repoClass = PersonRepository.class)
public class PersonEntity implements Serializable {

    public PersonEntity(){
        this.personType=1;
    }
    
    @Id
    @Basic
    @Column(name = "id", columnDefinition = "uniqueidentifier")
    @Type(type = "uuid-char")
    private UUID id;
    
    @Basic
    @Column(name = "first_name", nullable = false, length = 50, columnDefinition = "nvarchar(50)")
    private String firstName;
    
    @Basic
    @Column(name = "last_name", nullable = false, length = 50, columnDefinition = "nvarchar(50)")
    private String lastName;
    
    @Basic
    @Column(name = "father_name", length = 50, columnDefinition = "nvarchar(50)")
    private String fatherName;

@Basic
@FullTextField(termVector = TermVector.YES)
@Column(name = "full_name", columnDefinition = "as concat(first_name,' ',isnull(father_name,''),' ',last_name)", insertable = false, updatable = false)
private String fullName;

@Basic
@Column(name = "person_type", insertable = false, updatable = false)

@GenericField
private Integer personType;

以及继承个人实体的律师实体:

@Entity
@Accessors(chain = true)
@Getter
@Setter
@DiscriminatorValue("2")
@Indexed
@SyncAnnotation(convertor = ClientConvertor.class, repoClass = LawyerRepository.class)
public class LawyerEntity extends PersonEntity {

        public LawyerEntity(){
                this.setPersonType(2);
        }

    @Basic
    @Column(name = "bar_id")
    @GenericField
    private Integer barId;

    @Basic
    @Column(name = "bar_card_number")
    private Long barCardNumber;

    @Basic
    @Column(name = "bar_regisration_date")
    private LocalDate barRegistrationDate;

    @ManyToOne(targetEntity = BarEntity.class)
    @JoinColumn(foreignKey = @ForeignKey(name = "fk_lawyer_bar"),
            name = "bar_id", referencedColumnName = "id", insertable = false, updatable = false)
    @JsonIgnore
    private BarEntity bar;
}

当使用Sync休眠搜索自动索引策略时,UserEntity索引更新并包含索引中新插入的实体,TRACE输出:

2022-12-22 10:16:06.112 TRACE 68869 --- [nio-8080-exec-4] i.AfterCommitIndexingPlanSynchronization : Processing Transaction's beforeCompletion() phase for org.hibernate.engine.transaction.internal.TransactionImpl@5193eb5f.
2022-12-22 10:16:06.119 TRACE 68869 --- [nio-8080-exec-4] i.AfterCommitIndexingPlanSynchronization : Processing Transaction's afterCompletion() phase for org.hibernate.engine.transaction.internal.TransactionImpl@5193eb5f. Executing indexing plan.
2022-12-22 10:16:06.119 TRACE 68869 --- [nio-8080-exec-4] o.h.s.e.b.o.spi.SingletonTask            : Scheduling task 'Lucene indexing orchestrator for index 'User' - 9'.
2022-12-22 10:16:06.120 TRACE 68869 --- [rker thread - 2] o.h.s.e.b.o.spi.SingletonTask            : Running task 'Lucene indexing orchestrator for index 'User' - 9'
2022-12-22 10:16:06.120 TRACE 68869 --- [rker thread - 2] o.h.s.e.b.o.spi.BatchingExecutor         : Processing 1 works in executor 'Lucene indexing orchestrator for index 'User' - 9'
2022-12-22 10:16:06.132 TRACE 68869 --- [rker thread - 2] o.h.s.e.b.o.spi.BatchingExecutor         : Processed 1 works in executor 'Lucene indexing orchestrator for index 'User' - 9'
2022-12-22 10:16:06.132 TRACE 68869 --- [rker thread - 2] o.h.s.e.b.o.spi.SingletonTask            : Completed task 'Lucene indexing orchestrator for index 'User' - 9'

但是,当输入一个新人或律师时,索引并不反映更改,即使过了一段时间也不反映,我需要重新启动massindexer才能使其工作,它的输出与以前的日志类似,但在重新启动massindexer之前,它并不反映索引上的更改

2022-12-22 10:14:38.086 TRACE 68869 --- [nio-8080-exec-6] i.AfterCommitIndexingPlanSynchronization : Processing Transaction's beforeCompletion() phase for org.hibernate.engine.transaction.internal.TransactionImpl@6b9d9f5e.
2022-12-22 10:14:38.089 TRACE 68869 --- [nio-8080-exec-6] i.AfterCommitIndexingPlanSynchronization : Processing Transaction's afterCompletion() phase for org.hibernate.engine.transaction.internal.TransactionImpl@6b9d9f5e. Executing indexing plan.
2022-12-22 10:14:38.091 TRACE 68869 --- [nio-8080-exec-6] o.h.s.e.b.o.spi.SingletonTask            : Scheduling task 'Lucene indexing orchestrator for index 'Person' - 8'.
2022-12-22 10:14:38.091 TRACE 68869 --- [rker thread - 3] o.h.s.e.b.o.spi.SingletonTask            : Running task 'Lucene indexing orchestrator for index 'Person' - 8'
2022-12-22 10:14:38.092 TRACE 68869 --- [rker thread - 3] o.h.s.e.b.o.spi.BatchingExecutor         : Processing 1 works in executor 'Lucene indexing orchestrator for index 'Person' - 8'
2022-12-22 10:14:38.137 TRACE 68869 --- [rker thread - 3] o.h.s.e.b.o.spi.BatchingExecutor         : Processed 1 works in executor 'Lucene indexing orchestrator for index 'Person' - 8'
2022-12-22 10:14:38.138 TRACE 68869 --- [rker thread - 3] o.h.s.e.b.o.spi.SingletonTask            : Completed task 'Lucene indexing orchestrator for index 'Person' - 8'

我怎样才能让它在不重启大规模索引的情况下检测显示索引的变化呢?我也试过调用Hibernate搜索索引计划,但没有成功
我正在使用Hibernate搜索6.1.6.Final与lucene后端和Spring Boot 2.7.5
根据要求:用于搜索UserEntity(用户可以属于bar)的代码:

public List<UserEntity> findInAnyRole(String name, Integer barId, UUID[] role) {
        var session = sessionProvider.getSearchSession();
        var search = session.search(UserEntity.class);
        var res = search.where(f -> f.bool(
                b -> {
                    b.must(f.match().field("fullName").matching(name).fuzzy(2));
                    if (role != null && role.length > 0) {
                        b.must(f.bool(b2 -> {
                            for (var roleValue : role)
                                b2.should(f.match().field("roles.id").matching(roleValue));
                        }));
                    }
                    if (barId != null)
                        b.must(f.match().field("barId").matching(barId));
                }
        ));
        return res.fetchHits(10);
    }

对于个人实体:

public List<PersonEntity> findSimilar(@NotNull String name, String[] ids) {
        var session = sessionProvider.getSearchSession();
        var search = session.search(PersonEntity.class);
        var q=search.where(f -> f.bool().must(f.match().field("fullName").matching(name).fuzzy(2))
                .must(f.match().field("personType").matching(1))).sort(searchSortFactory -> searchSortFactory.score().desc());
        log.info(q.toQuery().queryString());
        return q.fetchHits(10);
    }

和律师实体:

public List<LawyerEntity> findSimilar(@NotNull String name, Integer barId) {
        var session = sessionProvider.getSearchSession();
        var search = session.search(LawyerEntity.class);
        var res = search.where(f -> f.match().field("fullName").matching(name).fuzzy(2));
        if (barId != null)
            res = search.where(f -> f.bool().must(f.match().field("fullName").matching(name).fuzzy(2))
                    .must(f.match().field("barId").matching(barId)));
        var list = res.fetchHits(10);
        return list;
    }
t3psigkw

t3psigkw1#

我猜你的问题就在这里:

@Column(name = "full_name", columnDefinition = "as concat(first_name,' ',isnull(father_name,''),' ',last_name)", insertable = false, updatable = false)
private String fullName;

由于您是在数据库端定义全名,因此只有从数据库加载时才会正确填充。第一次创建实体时,或者任何时候更改Java对象上的名或姓时,Java对象中的fullName属性将不会具有正确的值,直到从数据库加载回该属性。
我认为,当您创建实体时,fullNamenull,因此Hibernate搜索使用设置为nullfullName索引字段来索引您的实体,这说明您的查询(使用fullName字段上的 predicate )不匹配任何内容。
另一方面,使用质量索引器时,从数据库加载实体,并从数据库正确填充fullName
至于解决办法,可以:

  • 无论何时更新firstNamelastName,请始终手动更新fullName。这可能会带来不便。
  • 或者,如果您不需要在SQL查询中使用fullName,则不要在数据库中持久化fullName,不要向实体添加fullName属性,而只需声明一个用@javax.persistence.Transient注解的getFullName() getter,它在Java中执行以下连接操作:
@Transient
@FullTextField(termVector = TermVector.YES)
@IndexingDependency(derivedFrom = {
    @ObjectPath(@PropertyValue(propertyName = "firstName")),
    @ObjectPath(@PropertyValue(propertyName = "fatherName")),
    @ObjectPath(@PropertyValue(propertyName = "lastName"))
})
public String getFullName() {
  return firstName
      + ( fatherName == null ? "" : " " + fatherName )
      + " " + lastName;
}

有关@IndexingDependency的信息,请参见文档的此部分。

相关问题