lucene /休眠搜索-无法按集合中子类中的字段进行搜索

时间:2019-05-12 15:32:22

标签: java lucene hibernate-search

我有: Request实体具有Stage的集合,每个阶段具有StageItem的集合。阶段项目可以是几种类型,我在JPA / Hibernate SINGLE_TABLE中将它们用作带有区分项列的继承策略。

我需要我的Lucene查询来返回类型为A的阶段项目(类aDetail中的字段StageItemA)中具有特定详细信息的请求。我无法进行休眠搜索以查看子类aDetail中的字段StageItemA

因此该lucene查询不起作用(返回0个结果):

stages.stageItems.aDetail:blah

但是基于StageItem中的字段进行搜索是可行的:

stages.stageItems.comment:yuppie

使用Luke,我可以使用StageItem中的字段,例如stages.stageItems.comment,但不能使用StageItemA中的字段,例如stages.stageItems.aDetail

实体定义:

@Entity
@Table(name = "REQUEST")
@Indexed(index = "RequestIndex")
class Request implements Serializable {
    //...
    @OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
    @MapKeyColumn(name = "type", length = 50, nullable = false)
    @JoinTable(
            name = "REQUEST_STAGE",
            joinColumns = @JoinColumn(name = "REQUEST_ID", referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(name = "STAGE_ID", referencedColumnName = "id")
    )
    @IndexedEmbedded
    private Map<String, Stage> stages = new HashMap<>();
    //...
}

@Entity
@Table(name = "STAGE")
public class Stage implements Serializable {
    //...
    @OneToMany(fetch = FetchType.EAGER, targetEntity = StageItem.class, cascade = {
            CascadeType.ALL,
    }, orphanRemoval = true)
    @JoinTable(
            name = "STAGE_TO_STAGE_ITEM",
            joinColumns = @JoinColumn(name = "STAGE_ID"),
            inverseJoinColumns = @JoinColumn(name = "STAGE_ITEM_ID")
    )
    @Fetch(FetchMode.JOIN)
    @IndexedEmbedded
    private Set<StageItem> stageItems = new HashSet<>();
    //...
}

@Entity
@Table(name = "STAGE_ITEM")
@DiscriminatorColumn(name = "TYPE", discriminatorType = DiscriminatorType.STRING)
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class StageItem implements Serializable {
    //...
    @Column(name = "TYPE")
    @Field
    protected String type;

    @Column(name="COMMENT")
    @Field
    protected String comment;
    //...
}

@Entity
@DiscriminatorValue(value = "A")
public class StageItemA extends StageItem {
    //...
    @Column(name="A_DETAIL")
    @Field
    private String aDetail;
    //...
}

1 个答案:

答案 0 :(得分:0)

@IndexedEmbedded仅考虑属性的声明的类型,而不考虑运行时类型。因此,对于您当前的映射,@IndexedEmbedded将仅索引在类StageItem中声明的字段,而不索引在StageItemA中声明的字段。

有计划对此进行更改,并考虑到运行时多态性,但是我们还没有做到这一点:它似乎还不那么明显,因为在极端情况下,我们需要检测多个索引之间的索引模式中的冲突子类。请参阅HSEARCH-438以跟踪进度并查找更多信息。

与此同时,最简单的方法是让您声明一个方法和字段以在StageItem中返回null,并在StageItemA中对其进行覆盖以返回正确的值。

类似这样的东西:


@Entity
@Table(name = "STAGE_ITEM")
@DiscriminatorColumn(name = "TYPE", discriminatorType = DiscriminatorType.STRING)
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class StageItem implements Serializable {
    //...
    @Column(name = "TYPE")
    @Field
    protected String type;

    @Column(name="COMMENT")
    @Field
    protected String comment;
    //...

    @Field(name = "aDetail")
    @javax.persistence.Transient
    protected String getADetailForHibernateSearch() {
        return null;
    }
}

@Entity
@DiscriminatorValue(value = "A")
public class StageItemA extends StageItem {
    //...
    @Column(name="A_DETAIL")
    private String aDetail;
    //...

    @Override
    protected String getADetailForHibernateSearch() {
        return aDetail;
    }
}

主要缺点是索引瞬态方法会对性能产生负面影响:简而言之,由于Hibernate Search不知道数据来自何处,因此会考虑将任何更改为 any 属性需要重新索引,而以前,只有在修改了相关属性后,它才触发重新索引。不过,您可以尝试一下,在您的情况下,性能下降可能并不那么糟糕。