Lucene 之 Facet

 說到Facet,我還真找不到一個合適的中文詞彙來描述它,英文翻譯是方面,感受不夠貼切,你們也沒必要糾結它的中文叫法是啥,你只須要知道使用Facet能解決什麼類型的問題就好了,來看幾個典型的應用案例:java


 

 

        看了上面幾張圖,你們應該知道Facet是用來幹嗎的了,若是非要用語言描述Facet的用途,那Facet的用途就是根據域的域值進行分組統計,注意這 裏的域必須是FacetField,你Facet域的域值有幾個就會分幾組,並統計在Query查詢條件下各組的命中結果數量。但一般不須要顯示全部分 組,就如圖上面3張圖,通常都是顯示Top N 個分組便可。是否是以爲Facet和Group有點類似,對,看起來是有那麼一點類似,那二者到底有什麼區別呢?apache

 

Html代碼  收藏代碼數組

  1. They are two different lucene features:  app

  2.   

  3. Grouping was first released with Lucene 3.2, its related jira issue is LUCENE-1421: it allows to group search results by specified field. For example, if you group by the author field, then all documents with the same value in the author field fall into a single group. You will have a kind of tree as output. If you want to go deeper into using this lucene feature, this blog post should be useful.  ide

  4. Faceting was first released with Lucene 3.4, its related jira issue is LUCENE-3079: this feature doesn't group documents, it just tells you how many documents fall in a specific value of a facet. For example, if you have a facet based on the author field, you will receive a list of all your authors, and for each author you will know how many documents belong to that specific author. After, if you want to see those documents, you have to query one more time adding a specific filter (author=whatever). The faceted search is in fact based on browsing documents applying multiple filters to progressively reach the documents you're really interested in.  函數

    對不起,只有英文的說明,大意就是:Grouping分組功能是在跟隨Lucene 3.2穩定版首次發佈的,它容許你根據一個指定的域進行分組,舉個例子,若是你根據一個author域進行分組,那麼這個域的全部域值相同的索引文檔進行 落入到這個分組中。Facet是在跟隨Lucene3.4穩定版首次發佈的,facet並不對文檔進行分組,Facet只是告訴你某個Facet下每一個域 值的命中數量,舉個例子,若是你有個facet是基於author域的,那麼facet會返回author域下的每一個域值,以及每一個author域值下的 命中結果總數。若是你想查看每一個author域值下的命中結果,那麼你可能須要再發起 一次請求,經過添加一個filter如author=xxxx.  其實Facet搜索就是經過應用多個filter來讓用戶瀏覽索引文檔,使用戶逐步找到本身感興趣的索引文檔,一句話:Facet分組統計的目的是經過 統計的數量誘發你點擊的慾望,通常你看到數量多的,你會有點擊慾望,點擊進去了你本身會判斷是否是你感興趣的內容,若是不是,那麼你會點擊數據量次之的, 如此下去,逐步誘導你找到你感興趣的內容,這就是Facet功能設計的目的。說白了就是利用羊羣效應誘發你去點擊。post

 

       首先來你須要建立FacetField域,在建立以前你須要瞭解FacetField的是否分詞,存儲,位置信息等。看看FacetField源碼一切就知曉了。測試


    FacetField的域名稱都是
dummy, 域類型都是默認的DOCS_AND_FREQS_AND_POSITIONS即須要記錄Term頻率和Document頻率(即項向量)和位置信息。而 FieldType對於默認是Stored=false,而tokenized=true(即會進行分詞處理轉化爲多個Term),瞭解這些頗有必要。

       而後FacetField跟普通的Field同樣,須要添加到document中,而後document須要經過IndexWriter對象a調用addDocument寫入索引,但此時document須要作一個轉換過程,即ui

Java代碼  收藏代碼this

  1. FacetsConfig.build(DirectoryTaxonomyWriter writer,Document document);  

    咱們來看看FacetsConfig的build方法背地裏都幹了些什麼?

 


     首先定義了3個Map分別對應了3種類型的FacetField:FacetField,SortedSetDocValuesFacetField,AssociationFacetField, FacetField就是普通的Facet域,SortedSetDocValuesFacetField就是能夠用來排序的DocValuesField域,AssociationFacetField是用來自定義Facets的域,它能夠關聯任意的byte[]字節數組.把用戶添加的域用3個map分開後,分別用了3個函數進行處理,如圖:

     processFacetFields內部關鍵點代碼就是:

     pathToString就是把多個域值拼在一塊兒,好比:

Java代碼  收藏代碼

  1. new FacetField("Author"new String[] { "Bob" ,"Jack","Tom"})  

    那拼一塊兒後就是BobJackTom,而後建立了一個StringField且Store.NO,意思就是咱們add一個FacetField其實就是add了一個StringField,固然二者不能徹底等同。注意是if裏的條件:

ft.multiValued && (ft.hierarchical || ft.requireDimCount)即若是是多值域且(path有多個值或者須要統計facet總數),若是不是多值域,則會add一個BinaryDocValuesField域:

Java代碼  收藏代碼

  1. doc.add(new BinaryDocValuesField(indexFieldName, dedupAndEncode(ordinals.get())));  

    而後咱們經過IndexSearcher查詢的時候須要傳入FacetsCollector結果收集器,剩下的套路基本都是固定的,沒什麼好說的,以下:

Java代碼  收藏代碼

  1. FacetsCollector fc = new FacetsCollector();  

  2.   

  3.         searcher.search(new MatchAllDocsQuery(), null, fc);  

  4.   

  5.         List<FacetResult> results = new ArrayList<FacetResult>();  

  6.   

  7.         Facets facets = new FastTaxonomyFacetCounts(taxoReader, this.config, fc);  

  8.   

  9.         results.add(facets.getTopChildren(10"Author"));  

  10.         results.add(facets.getTopChildren(10"Publish Date"));  

  11.   

  12.         indexReader.close();  

  13.         taxoReader.close();  

     至於DrillDownQuery,他其實就是根據用戶傳入的path數組用BooleanQuery進行連接的:

 

     先用BooleanQuery把多個TermQuery用Or連接起來,再用ConstantScoreQuery包裝下,主要是爲了禁用查詢權重的。

    至於DrillSideways更不須要被它的外表迷惑了,其實他內部其實仍是根據傳入的IndexSearch和Facet結果收集器去查詢的:

       內部就是爲了包裝獲得一個DrillSidewaysQuery對象,最後仍是調用的IndexSearcher的search方法。

      

 

 

       下面是一個Facet使用簡單示例:

Java代碼  收藏代碼

  1. package com.yida.framework.lucene5.facet;  

  2.   

  3. import java.io.IOException;  

  4. import java.util.ArrayList;  

  5. import java.util.List;  

  6.   

  7. import org.apache.lucene.analysis.core.WhitespaceAnalyzer;  

  8. import org.apache.lucene.document.Document;  

  9. import org.apache.lucene.facet.DrillDownQuery;  

  10. import org.apache.lucene.facet.DrillSideways;  

  11. import org.apache.lucene.facet.FacetField;  

  12. import org.apache.lucene.facet.FacetResult;  

  13. import org.apache.lucene.facet.Facets;  

  14. import org.apache.lucene.facet.FacetsCollector;  

  15. import org.apache.lucene.facet.FacetsConfig;  

  16. import org.apache.lucene.facet.taxonomy.FastTaxonomyFacetCounts;  

  17. import org.apache.lucene.facet.taxonomy.TaxonomyReader;  

  18. import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;  

  19. import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter;  

  20. import org.apache.lucene.index.DirectoryReader;  

  21. import org.apache.lucene.index.IndexWriter;  

  22. import org.apache.lucene.index.IndexWriterConfig;  

  23. import org.apache.lucene.search.IndexSearcher;  

  24. import org.apache.lucene.search.MatchAllDocsQuery;  

  25. import org.apache.lucene.store.Directory;  

  26. import org.apache.lucene.store.RAMDirectory;  

  27.   

  28. /** 

  29.  * Facet簡單示例 

  30.  *  

  31.  * @author Lanxiaowei 

  32.  *  

  33.  */  

  34. public class SimpleFacetsExample {  

  35.     private final Directory indexDir = new RAMDirectory();  

  36.     private final Directory taxoDir = new RAMDirectory();  

  37.     private final FacetsConfig config = new FacetsConfig();  

  38.   

  39.     public SimpleFacetsExample() {  

  40.         this.config.setHierarchical("Author"true);  

  41.         this.config.setHierarchical("Publish Date"true);  

  42.     }  

  43.   

  44.     /** 

  45.      * 建立測試索引 

  46.      *  

  47.      * @throws IOException 

  48.      */  

  49.     private void index() throws IOException {  

  50.         IndexWriter indexWriter = new IndexWriter(this.indexDir,  

  51.                 new IndexWriterConfig(new WhitespaceAnalyzer())  

  52.                         .setOpenMode(IndexWriterConfig.OpenMode.CREATE));  

  53.   

  54.         DirectoryTaxonomyWriter taxoWriter = new DirectoryTaxonomyWriter(  

  55.                 this.taxoDir);  

  56.   

  57.         Document doc = new Document();  

  58.         doc.add(new FacetField("Author"new String[] { "Bob" }));  

  59.         doc.add(new FacetField("Publish Date"new String[] { "2010""10",  

  60.                 "15" }));  

  61.         indexWriter.addDocument(this.config.build(taxoWriter, doc));  

  62.   

  63.         doc = new Document();  

  64.         doc.add(new FacetField("Author"new String[] { "Lisa" }));  

  65.         doc.add(new FacetField("Publish Date"new String[] { "2010""10",  

  66.                 "20" }));  

  67.         indexWriter.addDocument(this.config.build(taxoWriter, doc));  

  68.   

  69.         doc = new Document();  

  70.         doc.add(new FacetField("Author"new String[] { "Lisa" }));  

  71.         doc.add(new FacetField("Publish Date",  

  72.                 new String[] { "2012""1""1" }));  

  73.         indexWriter.addDocument(this.config.build(taxoWriter, doc));  

  74.   

  75.         doc = new Document();  

  76.         doc.add(new FacetField("Author"new String[] { "Susan" }));  

  77.         doc.add(new FacetField("Publish Date",  

  78.                 new String[] { "2012""1""7" }));  

  79.         indexWriter.addDocument(this.config.build(taxoWriter, doc));  

  80.   

  81.         doc = new Document();  

  82.         doc.add(new FacetField("Author"new String[] { "Frank" }));  

  83.         doc.add(new FacetField("Publish Date",  

  84.                 new String[] { "1999""5""5" }));  

  85.         indexWriter.addDocument(this.config.build(taxoWriter, doc));  

  86.   

  87.         indexWriter.close();  

  88.         taxoWriter.close();  

  89.     }  

  90.   

  91.     private List<FacetResult> facetsWithSearch() throws IOException {  

  92.         DirectoryReader indexReader = DirectoryReader.open(this.indexDir);  

  93.         IndexSearcher searcher = new IndexSearcher(indexReader);  

  94.         TaxonomyReader taxoReader = new DirectoryTaxonomyReader(this.taxoDir);  

  95.   

  96.         FacetsCollector fc = new FacetsCollector();  

  97.   

  98.         FacetsCollector.search(searcher, new MatchAllDocsQuery(), 10, fc);  

  99.   

  100.         List<FacetResult> results = new ArrayList<FacetResult>();  

  101.   

  102.         Facets facets = new FastTaxonomyFacetCounts(taxoReader, this.config, fc);  

  103.         results.add(facets.getTopChildren(10"Author"new String[0]));  

  104.         results.add(facets.getTopChildren(10"Publish Date"new String[0]));  

  105.   

  106.         indexReader.close();  

  107.         taxoReader.close();  

  108.   

  109.         return results;  

  110.     }  

  111.   

  112.     private List<FacetResult> facetsOnly() throws IOException {  

  113.         DirectoryReader indexReader = DirectoryReader.open(this.indexDir);  

  114.         IndexSearcher searcher = new IndexSearcher(indexReader);  

  115.         TaxonomyReader taxoReader = new DirectoryTaxonomyReader(this.taxoDir);  

  116.   

  117.         FacetsCollector fc = new FacetsCollector();  

  118.   

  119.         searcher.search(new MatchAllDocsQuery(), null, fc);  

  120.   

  121.         List<FacetResult> results = new ArrayList<FacetResult>();  

  122.   

  123.         Facets facets = new FastTaxonomyFacetCounts(taxoReader, this.config, fc);  

  124.   

  125.         results.add(facets.getTopChildren(10"Author"));  

  126.         results.add(facets.getTopChildren(10"Publish Date"));  

  127.   

  128.         indexReader.close();  

  129.         taxoReader.close();  

  130.   

  131.         return results;  

  132.     }  

  133.   

  134.     private FacetResult drillDown() throws IOException {  

  135.         DirectoryReader indexReader = DirectoryReader.open(this.indexDir);  

  136.         IndexSearcher searcher = new IndexSearcher(indexReader);  

  137.         TaxonomyReader taxoReader = new DirectoryTaxonomyReader(this.taxoDir);  

  138.   

  139.           

  140.         DrillDownQuery q = new DrillDownQuery(this.config);  

  141.         q.add("Publish Date"new String[] { "2010" });  

  142.           

  143.         FacetsCollector fc = new FacetsCollector();  

  144.         FacetsCollector.search(searcher, q, 10, fc);  

  145.   

  146.         Facets facets = new FastTaxonomyFacetCounts(taxoReader, this.config, fc);  

  147.         FacetResult result = facets.getTopChildren(10"Author"new String[0]);  

  148.   

  149.         indexReader.close();  

  150.         taxoReader.close();  

  151.   

  152.         return result;  

  153.     }  

  154.   

  155.     private List<FacetResult> drillSideways() throws IOException {  

  156.         DirectoryReader indexReader = DirectoryReader.open(this.indexDir);  

  157.         IndexSearcher searcher = new IndexSearcher(indexReader);  

  158.         TaxonomyReader taxoReader = new DirectoryTaxonomyReader(this.taxoDir);  

  159.   

  160.         DrillDownQuery q = new DrillDownQuery(this.config);  

  161.   

  162.         q.add("Publish Date"new String[] { "2010" });  

  163.   

  164.         DrillSideways ds = new DrillSideways(searcher, this.config, taxoReader);  

  165.         DrillSideways.DrillSidewaysResult result = ds.search(q, 10);  

  166.   

  167.         List<FacetResult> facets = result.facets.getAllDims(10);  

  168.   

  169.         indexReader.close();  

  170.         taxoReader.close();  

  171.   

  172.         return facets;  

  173.     }  

  174.   

  175.     public List<FacetResult> runFacetOnly() throws IOException {  

  176.         index();  

  177.         return facetsOnly();  

  178.     }  

  179.   

  180.     public List<FacetResult> runSearch() throws IOException {  

  181.         index();  

  182.         return facetsWithSearch();  

  183.     }  

  184.   

  185.     public FacetResult runDrillDown() throws IOException {  

  186.         index();  

  187.         return drillDown();  

  188.     }  

  189.   

  190.     public List<FacetResult> runDrillSideways() throws IOException {  

  191.         index();  

  192.         return drillSideways();  

  193.     }  

  194.   

  195.     public static void main(String[] args) throws Exception {  

  196.         // one  

  197.         System.out.println("Facet counting example:");  

  198.         System.out.println("-----------------------");  

  199.         SimpleFacetsExample example = new SimpleFacetsExample();  

  200.         List<FacetResult> results1 = example.runFacetOnly();  

  201.         System.out.println("Author: " + results1.get(0));  

  202.         System.out.println("Publish Date: " + results1.get(1));  

  203.           

  204.           

  205.         // two  

  206.         System.out.println("Facet counting example (combined facets and search):");  

  207.         System.out.println("-----------------------");  

  208.         List<FacetResult> results = example.runSearch();  

  209.         System.out.println("Author: " + results.get(0));  

  210.         System.out.println("Publish Date: " + results.get(1));  

  211.           

  212.           

  213.         // three  

  214.         System.out.println("Facet drill-down example (Publish Date/2010):");  

  215.         System.out.println("---------------------------------------------");  

  216.         System.out.println("Author: " + example.runDrillDown());  

  217.   

  218.         // four  

  219.         System.out.println("Facet drill-sideways example (Publish Date/2010):");  

  220.         System.out.println("---------------------------------------------");  

  221.         for (FacetResult result : example.runDrillSideways()) {  

  222.             System.out.println(result);  

  223.         }  

  224.     }  

  225. }  

相關文章
相關標籤/搜索