官术网_书友最值得收藏!

3.3.11 使用Collector篩選搜索結果

Collector主要用來從一次查詢中收集原始結果。可以通過它遍歷查詢結果中的每個文檔。執行搜索的Searcher.search()方法可以接收Collector對象作為參數。查詢類每次匹配到一個文檔都會調用Collector對象上的collect(int doc)方法。下面是一個收集文檔,但不對文檔評分的例子:

        private static final String FIELD = "contents";


        public static void main(String[] args) throws Exception {
            // 建立使用內存索引的Lucene
            Directory directory = new RAMDirectory();


            Analyzer analyzer = new StandardAnalyzer();
            IndexWriterConfig iwc = new IndexWriterConfig(analyzer);
            IndexWriter writer = new IndexWriter(directory, iwc);


            // 索引一些文檔
            writer.addDocument(createDocument("1", "foo bar baz"));
            writer.addDocument(createDocument("2", "red green blue"));
            writer.addDocument(createDocument("3",
                    "The Lucene was made by Doug Cutting"));


            writer.close();


            IndexReader reader = DirectoryReader.open(directory);


            IndexSearcher searcher = new IndexSearcher(reader);


            Term t1 = new Term(FIELD, "lucene");
            TermQuery query = new TermQuery(t1);


            final BitSet bits = new BitSet(reader.maxDoc());
            searcher.search(query, new Collector() {
                private int docBase;


                //忽略評分器
                @Override
                public void setScorer(Scorer scorer) {
                }


                //允許文檔亂序
                public boolean acceptsDocsOutOfOrder() {
                    return true;
                }


                public void collect(int doc) {
                    bits.set(doc + docBase);
                }


                public void setNextReader(AtomicReaderContext context) {
                    this.docBase = context.docBase;
                }
            });


            System.out.println("結果數:" + bits.cardinality());
            for (int i = bits.nextSetBit(0); i >= 0; i = bits.nextSetBit(i + 1)) {
                System.out.println("文檔編號:" + i);
            }
        }


        private static Document createDocument(String id, String content) {
            Document doc = new Document();
            doc.add(new Field("id", id, StringField.TYPE_STORED));
            doc.add(new Field(FIELD, content, TextField.TYPE_STORED));
            return doc;
        }

例如,有個Collector的子類TopDocsCollector處理原始的查詢結果,并且返回最相關的N個文檔。

它是一個基類,用于做所有返回TopDocs輸出的類的父類。TopDocsCollector.topDocs()方法返回最相關的N個文檔。

例如:

        Query q = ...;
        IndexSearcher searcher = ...;
        TopDocsCollector<ScoreDoc> tdc = new MyTopsDocCollector(numResults);
        searcher.search(q, tdc); //傳遞一個查詢對象和一個Collector對象
        //給Searcher.search方法

TopDocsCollector接收一個優先隊列和一個返回結果的總數作為參數。TopScoreDocCollector是TopDocsCollector的子類,也是可以直接使用的類。使用TopScoreDocCollector返回最相關的10個文檔的例子如下:

        int hitsPerPage = 10;
        IndexSearcher searcher = new IndexSearcher(index, true);
        TopScoreDocCollector collector = TopScoreDocCollector.create(hitsPerPage,
        true);
        searcher.search(q, collector);
        ScoreDoc[] hits = collector.topDocs().scoreDocs;

一個會員可以發布多條信息,搜索的時候如何將會員發布的信息按每個會員一條的方式顯示。也就是說每個會員編號最多只顯示一條。每個會員最多只顯示和查詢詞最相關的一條信息。這個功能是在結果集而不是在索引庫上遍歷有效文檔,所以應該采用Collector而不是Filter。

可以按指定列排序,然后過濾信息。但是Searcher.search()方法不能同時接收Collector對象和Sort對象。只存在:

        searcher.search(query, collector);

對搜索結果首先按會員列排序,然后按相關度排序。找出每個會員最多只顯示和查詢詞最相關的一條信息。讓Collector把這樣的結果放入一個TopDocs對象。

可以擴展TopDocsCollector類。在collect()方法中構造一個新的ScoreDoc對象。

        private static final class MyTopsDocCollector extends
        TopDocsCollector<ScoreDoc> {
          private int idx = 0;
          private int base = 0;


          public MyTopsDocCollector(int size) {
            super(new HitQueue(size, false));
          }


          @Override
          protected TopDocs newTopDocs(ScoreDoc[] results, int start) {
            if (results == null) {
              return EMPTY_TOPDOCS;
            }


            float maxScore = Float.NaN;
            if (start == 0) {
              maxScore = results[0].score;
            } else {
              for (int i = pq.size(); i > 1; i--) { pq.pop(); }
              maxScore = pq.pop().score;
            }


            return new TopDocs(totalHits, results, maxScore);
          }


          @Override
          public void collect(int doc) throws IOException {
          ++totalHits;
          pq.insertWithOverflow(new ScoreDoc(doc + base, scores[idx++]));
        }


        @Override
        public void setNextReader(IndexReader reader, int docBase)
            throws IOException {
          base = docBase;
        }


        @Override
        public void setScorer(Scorer scorer) throws IOException {
          //不做任何事。隨機分配評分值
        }


        @Override
        public boolean acceptsDocsOutOfOrder() {
          return true;
        }
      }

Collector類的setScorer()方法是一個方法,當IndexSearcher實際執行搜索時,通過IndexSearcher傳入score。

對每個匹配的文檔,調用collect()方法,傳遞一個索引段內部的文檔編號給collect()方法。

會員發布的信息要一輪一輪地顯示,不是說折疊起來就顯示一條。比如會員1有兩條數據:信息1,信息2;會員2也有兩條數據:信息1,信息2,要的結果是會員1的信息1,會員2的信息1,會員1的信息2,會員2的信息2。

把每個會員的相關信息都存到一個優先隊列。所有的搜索結果就是每個會員組成的優先隊列。也就是說,優先隊列有很多。

主站蜘蛛池模板: 锦州市| 汽车| 来凤县| 望谟县| 广安市| 宜阳县| 上思县| 张家口市| 汪清县| 云浮市| 达孜县| 顺义区| 鹰潭市| 九寨沟县| 长葛市| 郯城县| 遂宁市| 大厂| 武山县| 德惠市| 大埔区| 灵寿县| 天长市| 抚顺市| 广河县| 云龙县| 南漳县| 黄山市| 宜君县| 乌兰浩特市| 新乡县| 从江县| 新津县| 凌源市| 太仆寺旗| 安阳市| 兴安盟| 阿合奇县| 沧源| 眉山市| 马边|