Hibernate-Search无法生成子类索引

125 阅读2分钟

官方文档:

docs.jboss.org/hibernate/s…

索引查看工具:

code.google.com/archive/p/l…

本文档记录Hibernate-Search遇到的坑。

1.是否支持继承结构

1.1无法搜索父类字段

在实际操作中,建立如下结构,查询SubDocument,无法检索Document中的key字段。

class Document {
    private Integer key;
}
class SubDocument extends Document {
    private Integer subInfo;
}

hibernate继承结构是通过如下注解实现的。

@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "doc_type")
@DiscriminatorValue("ARTICLE")

经过关键词检索,官方文档中唯一相关的是multi_tenancy.strategy: discriminator

但是它跟@Inheritance(strategy = InheritanceType.SINGLE_TABLE),

@DiscriminatorColumn(name = "xxx")并没有关系,

指的是多个应用程序之间产生的租户概念。

此外,官方文档再无提及,在官方demo中也未发现类似实现。

经过检索发现如下描述称hibernate-search默认不支持继承结构。

stackoverflow.com/questions/1…

经过测试发现,父类中的基本类型可正常查询,如下字段不能查询:

@IndexingDependency(reindexOnUpdate = ReindexOnUpdate.NO)
@IndexedEmbedded
@ManyToOne
@JoinColumn(name = "tree_id")
private Tree tree;

修改为如下实现可正常查询:

@GenericField(aggregable = Aggregable.NO, valueBridge = @ValueBridgeRef(type = DocumentBridge.class))
@ManyToOne
@JoinColumn(name = "tree_id")
private Tree tree;

public class DocumentBridge implements ValueBridge<Tree, String> {
    @Override
    public String toIndexedValue(Tree tree, ValueBridgeToIndexedValueContext valueBridgeToIndexedValueContext) {
        return tree == null ? null : tree.toString();
    }
}

是否@IndexedEmbedded对应的查询错误

1.2未建立子类索引文件

通过如下方式生成索引文件

SearchSession searchSession = Search.session(entityManager);
try {
    searchSession.massIndexer().startAndWait();
} catch (InterruptedException e) {
    LoggerUtil.getLogger().error("生成索引异常", e);
    Thread.currentThread().interrupt();
}

发现仅在Document索引文件夹下存在内容,在SubDocument中都是空的。

stackoverflow.com/questions/1…

参考这个回答,将Document上的Indexed注解去掉,在SubDocument索引文件夹生成了内容。

2.搜索问题

2.1should如何实现or

where ( conditionA or conditionB) and conditionC如何用query实现

SearchResult<Article> articlePage = Search.session(entityManager).search(Article.class)
        .where(f -> f.bool(b -> {
            b.must(ff -> ff.bool()
                    .should(f.match().field(TITLE).matching(searchText))
                    .should(f.match().field(CONTENT).matching(searchText).skipAnalysis())
            );
            b.must(ff -> ff.bool(
                    bb -> {
                        for (Tree treeItem : treeList) {
                            bb.should(f.match().field(TREE).matching(treeItem));
                        }
                    }
            ));
            b.must(f.match().field(PUBLISH_FLAG).matching(publishFlag));
            b.must(f.match().field(DELETED).matching(false));
        }))
        .fetch(offset, pageSize);

错误实现:

SearchResult<Article> articlePage = Search.session(entityManager).search(Article.class)
        .where(f -> f.bool(b -> {
            b.must(f.matchAll());
            for (Tree treeItem : treeList) {
                b.should(f.match().field("tree").matching(treeItem));
            }
            b.must(f.match().fields("title", "content").matching(searchLike).skipAnalysis());
            b.must(f.match().field("publishFlag").matching(publishFlag));
            b.must(f.match().field("deleted").matching(false));
        }))
        .fetch(offset, pageSize);

没有现成的IN SQL,使用should替代or需要外层封装must;

fields虽然是or的意思,但是对应的analyzer不同。

@FullTextField(analyzer = "enHtmlAnalyzer", norms = Norms.NO)
private String content;
@FullTextField(analyzer = "normalText")
private String title;