在hibernate搜索中通过join-table具有多对多关系时,索引不一致

时间:2014-06-26 17:11:17

标签: hibernate lucene many-to-many hibernate-search jointable

通过hibernate搜索我有lucene的索引问题:

产品领域:

    @Entity
    @Table(name="T_PRD")
    @Indexed
    public class Product implements java.io.Serializable {
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "T_TMPL_ATTR_VALUE", joinColumns = { @JoinColumn(name = "EntityId", unique=false) }, inverseJoinColumns = { @JoinColumn(name = "AttrId", unique=false) }, uniqueConstraints=@UniqueConstraint(columnNames={"EntityId","AttrId"}))
    @IndexedEmbedded(prefix="prd.ca.")
    private Set<TemplateAttribute> customTemplateAttributes;
}

TemplateAttribute Domain:

@Entity
@Table(name = "T_TMPL_ATTRS")
public class TemplateAttribute implements java.io.Serializable {

    @OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.LAZY, mappedBy = "templateAttribute")
    @IndexedEmbedded
    private Set<TemplateAttributeValue> templateAttrValues = new HashSet<TemplateAttributeValue>(0);

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "T_TMPL_ATTR_VALUE", joinColumns = { @JoinColumn(name = "AttrId", unique=false) }, inverseJoinColumns = { @JoinColumn(name = "EntityId", unique=false)}, uniqueConstraints=@UniqueConstraint(columnNames={"EntityId","AttrId"}))


    @ContainedIn
    private Set<Product> product;

@Column(name = "DefaultValue")
private String defaultValue;

}

TemplateAttributeValue域(桥接表,其中 attrValue 字段包含产品特定值):

@Entity
@Table(name = "T_TMPL_ATTR_VALUE")
public class TemplateAttributeValue implements java.io.Serializable {

    @DocumentId(name="id")
    @EmbeddedId
    @AttributeOverrides( {
    @AttributeOverride(name = "entityId", column = @Column(name = "EntityId", nullable = false)),
    @AttributeOverride(name = "attrId", column = @Column(name = "AttrId", nullable = false)) })
    @FieldBridge(impl = TemplateAttributeCompositeKeyBridge.class)
    public TemplateAttributeValueId getId() {
        return this.id;
    }

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "AttrId", nullable = false, insertable = false, updatable = false)
    @ContainedIn
    public TemplateAttribute getTemplateAttribute() {
        return this.templateAttribute;
    }

    @Column(name = "AttrValue")
    @Field(index = Index.YES, analyze = Analyze.YES, norms = Norms.NO, store = Store.NO)
    public String getAttrValue() {
        return this.attrValue==null?"":this.attrValue;
    }
}

我打电话给doIndex方法如下:

private void doIndex() throws InterruptedException {
    Session session = getSessionFactory().openSession();
    session.enableFilter("onlyProductTemplate");
    FullTextSession fullTextSession = Search.getFullTextSession(session);
    fullTextSession.createIndexer().startAndWait();

    fullTextSession.close();
}

因此,让我们假设以下数据为例:

Product:

ID | Name
----------
 1 | Prd1
 2 | Prd2
 3 | Prd3

Template Attribute:

AttrId | DefaultValue
---------------------
1 | Template1
2 | Template2


Template Attribute Value:

AttrId | EntityId | AttrValue
-----------------------------
1 | 1 | Template1
2 | 1 | Template2_modified
1 | 2 | Template1Updated
1 | 2 | Template2
1 | 3 | Template1
2 | 3 | Template2_newValue

因此,当我为产品实体创建索引时,每个产品都会生成模板属性值中定义的索引所有AttrValue

因此,当特定产品的搜索具有某些匹配的任何模板属性值时,它将返回列表中的所有产品。

那么如何在hibernate搜索中解决这个问题。

1 个答案:

答案 0 :(得分:0)

我通过实施StringBridge得到了解决方案,如下所示:

    @Override
    public String objectToString(Object value) {
        if(value != null) {
            String templateType = null;  
            if(value instanceof Set) {
                StringBuilder strBuild = new StringBuilder();
                Set<TemplateAttribute> setOfTempAttr = (Set<TemplateAttribute>) value;
                for(TemplateAttribute tempValue : setOfTempAttr) {
                    int productID = tempValue.getProduct().getProductId();
                    Set<TemplateAttributeValue> setOfTempAttrValues = tempValue.getTemplateAttrValues();

                    for (TemplateAttributeValue taValue : setOfTempAttrValues) {
                        int entityID = taValue.getId().getEntityId();
                        if(entityID == productID) {
                            strBuild.append(" " + taValue.getAttrValue());
                        }

                    }
                }
                return strBuild.toString();
            } else if(value instanceof String) {
                templateType = (String) value;
            }
            return templateType;
        }
        return null;
}

意味着我们需要忽略要为其不属于的产品编制索引的attrValue 。再一次更改删除@ indexedEmbedded / @ ContainedIn注释并定义如下:

    @Field(index = Index.YES, analyze = Analyze.YES, norms = Norms.NO, store = Store.NO)
    @FieldBridge(impl = TemplateAttributeValueProductFieldBridge.class)
 private Set<TemplateAttribute> customTemplateAttributes;