自己动手写分布式搜索引擎
上QQ阅读APP看书,第一时间看更新

3.3.14 列合并

可以把鱼头和鱼尾分开做成不同的菜。假设要开发一个新闻检索系统,文章索引可能不会经常改变,但是评论索引会经常改变。所以可以把文章和评论独立建立索引,但可以同时查询。评论索引中包含文章索引的id列,如图3-13所示。

图3-13 列合并查询

通过合并查询,可以将不同的部分分别按文档来存储,这将带来更多的灵活性,但是会增加更多的执行时间。

查询时合并封装在JoinUtil.createJoinQuery()方法中,它需要下面几个参数。

● fromField:连接的来源列。

● toField:连接的目的列。

● fromQuery:指定查询的词。通常是用户指定的查询。

● fromSearcher. fromQuery:执行查询的搜索器找那个索引。

● multipleValuesPerDocument:指定fromField是否为多值列,也就是是否每个文档有不止一个值。

静态合并方法返回一个查询,能够在IndexSearcher上执行这个查询,用于检索所有在to列和找到的from词相匹配的文档。只有用于连接的条目展现给用户,而完全隐藏实际的实现方法,在保证API向后兼容性的同时允许Lucene实现者改变实现方法。

通过两步搜索实现在经过索引的词之上做查询时间合并:第一步从from域内(在我们的例子中,为文章标记域)搜集所有与from查询匹配的术语;第二步返回所有在to域(在我们的例子中,为评论文档中的文章标记域)中有匹配术语的文档给第一步从搜集到的术语。

返回给静态合并方法的查询能够作为一个静态合并方法的参数在不同的IndexSearcher上执行。这种灵活性允许合并来自不同索引中的数据,只要toField确实存在于索引之中。在这个例子中,意味着文章和评论数据能够位于两个不同的索引之中。文章索引可能不会经常改变,但是评论索引会经常改变。这样就可以去微调这些索引来满足各自特定的需求。

例如,搜索文章标题是byte norms的评论:

        IndexSearcher articleSearcher = ... //打开文章索引
        IndexSearcher commentSearcher = ... //打开评论索引
        String fromField = "id";
        boolean multipleValuesPerDocument = false;
        String toField = "article_id";
        // 这个查询产生id是2的文章作为结果
        BooleanQuery fromQuery = new BooleanQuery();
        fromQuery.add(new TermQuery(new Term("title", "byte")),
                    BooleanClause.Occur.MUST); // byte这个词必须出现
        fromQuery.add(new TermQuery(new Term("title", "norms")),
                    BooleanClause.Occur.MUST); // norms这个词也必须出现
        Query joinQuery = JoinUtil.createJoinQuery(fromField,
        multipleValuesPerDocument,
                                          toField, fromQuery, articleSearcher);
        TopDocs topDocs = commentSearcher.search(joinQuery, 10);