Lucene5学习之Facet(续)

简介:

     默认Facet是统计落入某一组域值的总数的,然后按照总数从大到小排序,判定规则是域值是否相同,其实还可以根据域值是否在某个范围内来判定是否落入某一个分组。这里说的范围就是通过Range定义的,比如:

Java代码   收藏代码
  1.        /**1小时之前的毫秒数*/  
  2. final LongRange PAST_HOUR = new LongRange("Past hour", this.nowSec - 3600L,  
  3.         true, this.nowSec, true);  
  4. /**6小时之前的毫秒数*/  
  5. final LongRange PAST_SIX_HOURS = new LongRange("Past six hours",  
  6.         this.nowSec - 21600L, true, this.nowSec, true);  
  7. /**24小时之前的毫秒数*/  
  8. final LongRange PAST_DAY = new LongRange("Past day", this.nowSec - 86400L,  
  9.         true, this.nowSec, true);  

    这里定义了3个数字范围,比如1个小时之前的毫秒数至当前时间毫秒数之间的范围,剩余两个类似,然后就可以根据定义的范围来创建Facet:

Java代码   收藏代码
  1.         //定义3个Facet: 统计   
  2. //[过去一小时之前-->当前时间]  [过去6小时之前-->当前时间]  [过去24小时之前-->当前时间]  
  3. Facets facets = new LongRangeFacetCounts("timestamp", fc,  
  4.     new LongRange[] { this.PAST_HOUR, this.PAST_SIX_HOURS,this.PAST_DAY });  

   这样就能根据自定义范围去统计了,只要当前域的域值落在这个范围内,则这个facet分组内计数加1.完整示例代码如下:

Java代码   收藏代码
  1. package com.yida.framework.lucene5.facet;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import org.apache.lucene.analysis.core.WhitespaceAnalyzer;  
  6. import org.apache.lucene.document.Document;  
  7. import org.apache.lucene.document.Field;  
  8. import org.apache.lucene.document.LongField;  
  9. import org.apache.lucene.document.NumericDocValuesField;  
  10. import org.apache.lucene.facet.DrillDownQuery;  
  11. import org.apache.lucene.facet.FacetResult;  
  12. import org.apache.lucene.facet.Facets;  
  13. import org.apache.lucene.facet.FacetsCollector;  
  14. import org.apache.lucene.facet.FacetsConfig;  
  15. import org.apache.lucene.facet.range.LongRange;  
  16. import org.apache.lucene.facet.range.LongRangeFacetCounts;  
  17. import org.apache.lucene.index.DirectoryReader;  
  18. import org.apache.lucene.index.IndexWriter;  
  19. import org.apache.lucene.index.IndexWriterConfig;  
  20. import org.apache.lucene.search.IndexSearcher;  
  21. import org.apache.lucene.search.MatchAllDocsQuery;  
  22. import org.apache.lucene.search.NumericRangeQuery;  
  23. import org.apache.lucene.search.ScoreDoc;  
  24. import org.apache.lucene.search.TopDocs;  
  25. import org.apache.lucene.store.Directory;  
  26. import org.apache.lucene.store.RAMDirectory;  
  27.   
  28. public class RangeFacetsExample {  
  29.     private final Directory indexDir = new RAMDirectory();  
  30.     private IndexSearcher searcher;  
  31.     /**当前时间的毫秒数*/  
  32.     private final long nowSec = System.currentTimeMillis();  
  33.   
  34.     /**1小时之前的毫秒数*/  
  35.     final LongRange PAST_HOUR = new LongRange("Past hour", this.nowSec - 3600L,  
  36.             true, this.nowSec, true);  
  37.     /**6小时之前的毫秒数*/  
  38.     final LongRange PAST_SIX_HOURS = new LongRange("Past six hours",  
  39.             this.nowSec - 21600L, true, this.nowSec, true);  
  40.     /**24小时之前的毫秒数*/  
  41.     final LongRange PAST_DAY = new LongRange("Past day", this.nowSec - 86400L,  
  42.             true, this.nowSec, true);  
  43.   
  44.     /** 
  45.      * 创建测试索引 
  46.      * @throws IOException 
  47.      */  
  48.     public void index() throws IOException {  
  49.         IndexWriter indexWriter = new IndexWriter(this.indexDir,  
  50.                 new IndexWriterConfig(new WhitespaceAnalyzer())  
  51.                         .setOpenMode(IndexWriterConfig.OpenMode.CREATE));  
  52.   
  53.         /** 
  54.          * 每次按[1000*i]这个斜率递减创建一个索引 
  55.          */  
  56.         for (int i = 0; i < 100; i++) {  
  57.             Document doc = new Document();  
  58.             long then = this.nowSec - i * 1000;  
  59.   
  60.             doc.add(new NumericDocValuesField("timestamp", then));  
  61.   
  62.             doc.add(new LongField("timestamp", then, Field.Store.YES));  
  63.             indexWriter.addDocument(doc);  
  64.         }  
  65.           
  66.         this.searcher = new IndexSearcher(DirectoryReader.open(indexWriter,  
  67.                 true));  
  68.         indexWriter.close();  
  69.     }  
  70.   
  71.     /** 
  72.      * 获取FacetConfig配置对象 
  73.      * @return 
  74.      */  
  75.     private FacetsConfig getConfig() {  
  76.         return new FacetsConfig();  
  77.     }  
  78.   
  79.     public FacetResult search() throws IOException {  
  80.         /**创建Facet结果收集器*/  
  81.         FacetsCollector fc = new FacetsCollector();  
  82.         TopDocs topDocs = FacetsCollector.search(this.searcher, new MatchAllDocsQuery(), 20, fc);  
  83.         ScoreDoc[] scoreDocs = topDocs.scoreDocs;  
  84.         for(ScoreDoc scoreDoc : scoreDocs) {  
  85.             int docId = scoreDoc.doc;  
  86.             Document doc = searcher.doc(docId);  
  87.             System.out.println(scoreDoc.doc + "\t" + doc.get("timestamp"));  
  88.         }  
  89.         //定义3个Facet: 统计   
  90.         //[过去一小时之前-->当前时间]  [过去6小时之前-->当前时间]  [过去24小时之前-->当前时间]  
  91.         Facets facets = new LongRangeFacetCounts("timestamp", fc,  
  92.                 new LongRange[] { this.PAST_HOUR, this.PAST_SIX_HOURS,  
  93.                         this.PAST_DAY });  
  94.           
  95.         return facets.getTopChildren(10, "timestamp", new String[0]);  
  96.     }  
  97.   
  98.     /** 
  99.      * 使用DrillDownQuery进行Facet统计 
  100.      * @param range 
  101.      * @return 
  102.      * @throws IOException 
  103.      */  
  104.     public TopDocs drillDown(LongRange range) throws IOException {  
  105.         DrillDownQuery q = new DrillDownQuery(getConfig());  
  106.   
  107.         q.add("timestamp", NumericRangeQuery.newLongRange("timestamp",  
  108.                 Long.valueOf(range.min), Long.valueOf(range.max),  
  109.                 range.minInclusive, range.maxInclusive));  
  110.   
  111.         return this.searcher.search(q, 10);  
  112.     }  
  113.   
  114.     public void close() throws IOException {  
  115.         this.searcher.getIndexReader().close();  
  116.         this.indexDir.close();  
  117.     }  
  118.   
  119.     public static void main(String[] args) throws Exception {  
  120.         RangeFacetsExample example = new RangeFacetsExample();  
  121.         example.index();  
  122.   
  123.         System.out.println("Facet counting example:");  
  124.         System.out.println("-----------------------");  
  125.         System.out.println(example.search());  
  126.   
  127.         System.out.println("\n");  
  128.           
  129.         //只统计6个小时之前的Facet  
  130.         System.out  
  131.                 .println("Facet drill-down example (timestamp/Past six hours):");  
  132.         System.out.println("---------------------------------------------");  
  133.         TopDocs hits = example.drillDown(example.PAST_SIX_HOURS);  
  134.         System.out.println(hits.totalHits + " totalHits");  
  135.   
  136.         example.close();  
  137.     }  
  138. }  

   我们在通过FacetsCollector.search进行搜索时,其实是可以传入排序器的,这时我们在创建索引时就需要使用SortedSetDocValuesFacetField,这样FacetsCollector.search返回的TopDocs就是经过排序的了,这一点需要注意。具体示例代码如下:

Java代码   收藏代码
  1. package com.yida.framework.lucene5.facet;  
  2. import java.io.IOException;  
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import org.apache.lucene.analysis.core.WhitespaceAnalyzer;  
  7. import org.apache.lucene.document.Document;  
  8. import org.apache.lucene.facet.DrillDownQuery;  
  9. import org.apache.lucene.facet.FacetResult;  
  10. import org.apache.lucene.facet.Facets;  
  11. import org.apache.lucene.facet.FacetsCollector;  
  12. import org.apache.lucene.facet.FacetsConfig;  
  13. import org.apache.lucene.facet.sortedset.DefaultSortedSetDocValuesReaderState;  
  14. import org.apache.lucene.facet.sortedset.SortedSetDocValuesFacetCounts;  
  15. import org.apache.lucene.facet.sortedset.SortedSetDocValuesFacetField;  
  16. import org.apache.lucene.facet.sortedset.SortedSetDocValuesReaderState;  
  17. import org.apache.lucene.index.DirectoryReader;  
  18. import org.apache.lucene.index.IndexWriter;  
  19. import org.apache.lucene.index.IndexWriterConfig;  
  20. import org.apache.lucene.search.IndexSearcher;  
  21. import org.apache.lucene.search.MatchAllDocsQuery;  
  22. import org.apache.lucene.search.Sort;  
  23. import org.apache.lucene.search.SortField;  
  24. import org.apache.lucene.search.SortField.Type;  
  25. import org.apache.lucene.search.TopDocs;  
  26. import org.apache.lucene.store.Directory;  
  27. import org.apache.lucene.store.RAMDirectory;  
  28. public class SimpleSortedSetFacetsExample {  
  29.     private final Directory indexDir = new RAMDirectory();  
  30.     private final FacetsConfig config = new FacetsConfig();  
  31.   
  32.     private void index() throws IOException {  
  33.         IndexWriter indexWriter = new IndexWriter(this.indexDir,  
  34.                 new IndexWriterConfig(new WhitespaceAnalyzer())  
  35.                         .setOpenMode(IndexWriterConfig.OpenMode.CREATE));  
  36.   
  37.         Document doc = new Document();  
  38.         doc.add(new SortedSetDocValuesFacetField("Author", "Bob"));  
  39.         doc.add(new SortedSetDocValuesFacetField("Publish Year", "2010"));  
  40.         indexWriter.addDocument(this.config.build(doc));  
  41.   
  42.         doc = new Document();  
  43.         doc.add(new SortedSetDocValuesFacetField("Author", "Lisa"));  
  44.         doc.add(new SortedSetDocValuesFacetField("Publish Year", "2010"));  
  45.         indexWriter.addDocument(this.config.build(doc));  
  46.   
  47.         doc = new Document();  
  48.         doc.add(new SortedSetDocValuesFacetField("Author", "Lisa"));  
  49.         doc.add(new SortedSetDocValuesFacetField("Publish Year", "2012"));  
  50.         indexWriter.addDocument(this.config.build(doc));  
  51.   
  52.         doc = new Document();  
  53.         doc.add(new SortedSetDocValuesFacetField("Author", "Susan"));  
  54.         doc.add(new SortedSetDocValuesFacetField("Publish Year", "2012"));  
  55.         indexWriter.addDocument(this.config.build(doc));  
  56.   
  57.         doc = new Document();  
  58.         doc.add(new SortedSetDocValuesFacetField("Author", "Frank"));  
  59.         doc.add(new SortedSetDocValuesFacetField("Publish Year", "1999"));  
  60.         indexWriter.addDocument(this.config.build(doc));  
  61.   
  62.         indexWriter.close();  
  63.     }  
  64.   
  65.     private List  search()  throws IOException {  
  66.         DirectoryReader indexReader = DirectoryReader.open(this.indexDir);  
  67.         IndexSearcher searcher = new IndexSearcher(indexReader);  
  68.         SortedSetDocValuesReaderState state = new DefaultSortedSetDocValuesReaderState(  
  69.                 indexReader);  
  70.   
  71.         FacetsCollector fc = new FacetsCollector();  
  72.           
  73.         Sort sort = new Sort(new SortField("Author", Type.INT, false));  
  74.         //FacetsCollector.search(searcher, new MatchAllDocsQuery(), 10, fc);  
  75.         TopDocs topDocs = FacetsCollector.search(searcher,new MatchAllDocsQuery(),null,10,sort,true,false,fc);  
  76.   
  77.         Facets facets = new SortedSetDocValuesFacetCounts(state, fc);  
  78.   
  79.         List  results =  new ArrayList ();  
  80.         results.add(facets.getTopChildren(10, "Author", new String[0]));  
  81.         results.add(facets.getTopChildren(10, "Publish Year", new String[0]));  
  82.         indexReader.close();  
  83.   
  84.         return results;  
  85.     }  
  86.   
  87.     private FacetResult drillDown() throws IOException {  
  88.         DirectoryReader indexReader = DirectoryReader.open(this.indexDir);  
  89.         IndexSearcher searcher = new IndexSearcher(indexReader);  
  90.         SortedSetDocValuesReaderState state = new DefaultSortedSetDocValuesReaderState(  
  91.                 indexReader);  
  92.   
  93.         DrillDownQuery q = new DrillDownQuery(this.config);  
  94.         q.add("Publish Year", new String[] { "2010" });  
  95.         FacetsCollector fc = new FacetsCollector();  
  96.         FacetsCollector.search(searcher, q, 10, fc);  
  97.   
  98.         Facets facets = new SortedSetDocValuesFacetCounts(state, fc);  
  99.         FacetResult result = facets.getTopChildren(10, "Author", new String[0]);  
  100.         indexReader.close();  
  101.   
  102.         return result;  
  103.     }  
  104.   
  105.     public List  runSearch()  throws IOException {  
  106.         index();  
  107.         return search();  
  108.     }  
  109.   
  110.     public FacetResult runDrillDown() throws IOException {  
  111.         index();  
  112.         return drillDown();  
  113.     }  
  114.   
  115.     public static void main(String[] args) throws Exception {  
  116.         System.out.println("Facet counting example:");  
  117.         System.out.println("-----------------------");  
  118.         SimpleSortedSetFacetsExample example = new SimpleSortedSetFacetsExample();  
  119.         List  results = example.runSearch();  
  120.         System.out.println("Author: " + results.get(0));  
  121.         System.out.println("Publish Year: " + results.get(0));  
  122.   
  123.         System.out.println("\n");  
  124.         System.out.println("Facet drill-down example (Publish Year/2010):");  
  125.         System.out.println("---------------------------------------------");  
  126.         System.out.println("Author: " + example.runDrillDown());  
  127.     }  
  128. }  

    前面我们在定义Facet时,即可以不指定域名,比如:

Java代码   收藏代码
  1. Facets facets = new FastTaxonomyFacetCounts(taxoReader, this.config, fc);  

    这时默认会根据我们定义的FacetField去决定定义几个Facet进行统计,你可以指定只对指定域定义Facet,这样就可以值返回你关心的Facet统计数据,比如:

Java代码   收藏代码
  1. Facets author = new FastTaxonomyFacetCounts("author", taxoReader,  
  2.                 this.config, fc);  

    具体完整示例代码如下:

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.FacetField;  
  10. import org.apache.lucene.facet.FacetResult;  
  11. import org.apache.lucene.facet.Facets;  
  12. import org.apache.lucene.facet.FacetsCollector;  
  13. import org.apache.lucene.facet.FacetsConfig;  
  14. import org.apache.lucene.facet.taxonomy.FastTaxonomyFacetCounts;  
  15. import org.apache.lucene.facet.taxonomy.TaxonomyReader;  
  16. import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;  
  17. import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter;  
  18. import org.apache.lucene.index.DirectoryReader;  
  19. import org.apache.lucene.index.IndexWriter;  
  20. import org.apache.lucene.index.IndexWriterConfig;  
  21. import org.apache.lucene.search.IndexSearcher;  
  22. import org.apache.lucene.search.MatchAllDocsQuery;  
  23. import org.apache.lucene.store.Directory;  
  24. import org.apache.lucene.store.RAMDirectory;  
  25. /** 
  26.  * 根据指定域加载特定Facet Count 
  27.  * @author Lanxiaowei 
  28.  * 
  29.  */  
  30. public class MultiCategoryListsFacetsExample {  
  31.     private final Directory indexDir = new RAMDirectory();  
  32.     private final Directory taxoDir = new RAMDirectory();  
  33.     private final FacetsConfig config = new FacetsConfig();  
  34.   
  35.     public MultiCategoryListsFacetsExample() {  
  36.         //定义  域别名  
  37.         this.config.setIndexFieldName("Author", "author");  
  38.         this.config.setIndexFieldName("Publish Date", "pubdate");  
  39.           
  40.         // 设置Publish Date为多值域  
  41.         this.config.setHierarchical("Publish Date", true);  
  42.     }  
  43.   
  44.     /** 
  45.      * 创建测试索引 
  46.      * @throws IOException 
  47.      */  
  48.     private void index() throws IOException {  
  49.         IndexWriter indexWriter = new IndexWriter(this.indexDir,  
  50.                 new IndexWriterConfig(new WhitespaceAnalyzer())  
  51.                         .setOpenMode(IndexWriterConfig.OpenMode.CREATE));  
  52.   
  53.         DirectoryTaxonomyWriter taxoWriter = new DirectoryTaxonomyWriter(  
  54.                 this.taxoDir);  
  55.   
  56.         Document doc = new Document();  
  57.         doc.add(new FacetField("Author", new String[] { "Bob" }));  
  58.         doc.add(new FacetField("Publish Date", new String[] { "2010", "10",  
  59.                 "15" }));  
  60.         indexWriter.addDocument(this.config.build(taxoWriter, doc));  
  61.   
  62.         doc = new Document();  
  63.         doc.add(new FacetField("Author", new String[] { "Lisa" }));  
  64.         doc.add(new FacetField("Publish Date", new String[] { "2010", "10",  
  65.                 "20" }));  
  66.         indexWriter.addDocument(this.config.build(taxoWriter, doc));  
  67.   
  68.         doc = new Document();  
  69.         doc.add(new FacetField("Author", new String[] { "Lisa" }));  
  70.         doc.add(new FacetField("Publish Date",  
  71.                 new String[] { "2012", "1", "1" }));  
  72.         indexWriter.addDocument(this.config.build(taxoWriter, doc));  
  73.   
  74.         doc = new Document();  
  75.         doc.add(new FacetField("Author", new String[] { "Susan" }));  
  76.         doc.add(new FacetField("Publish Date",  
  77.                 new String[] { "2012", "1", "7" }));  
  78.         indexWriter.addDocument(this.config.build(taxoWriter, doc));  
  79.   
  80.         doc = new Document();  
  81.         doc.add(new FacetField("Author", new String[] { "Frank" }));  
  82.         doc.add(new FacetField("Publish Date",  
  83.                 new String[] { "1999", "5", "5" }));  
  84.         indexWriter.addDocument(this.config.build(taxoWriter, doc));  
  85.   
  86.         indexWriter.close();  
  87.         taxoWriter.close();  
  88.     }  
  89.   
  90.     private List  search()  throws IOException {  
  91.         DirectoryReader indexReader = DirectoryReader.open(this.indexDir);  
  92.         IndexSearcher searcher = new IndexSearcher(indexReader);  
  93.         TaxonomyReader taxoReader = new DirectoryTaxonomyReader(this.taxoDir);  
  94.   
  95.         FacetsCollector fc = new FacetsCollector();  
  96.   
  97.         FacetsCollector.search(searcher, new MatchAllDocsQuery(), 10, fc);  
  98.   
  99.         List  results =  new ArrayList ();  
  100.   
  101.         //定义author域的Facet,  
  102.         //FastTaxonomyFacetCounts第一个构造参数指定域名称,  
  103.         //则只统计指定域的Facet总数,不指定域名称,则默认会统计所有FacetField域的总数  
  104.         //这就跟SQL中的select * from...和 select name from ...差不多  
  105.         Facets author = new FastTaxonomyFacetCounts("author", taxoReader,  
  106.                 this.config, fc);  
  107.         results.add(author.getTopChildren(10, "Author", new String[0]));  
  108.   
  109.         //定义pubdate域的Facet  
  110.         Facets pubDate = new FastTaxonomyFacetCounts("pubdate", taxoReader,  
  111.                 this.config, fc);  
  112.         results.add(pubDate.getTopChildren(10, "Publish Date", new String[0]));  
  113.   
  114.         indexReader.close();  
  115.         taxoReader.close();  
  116.   
  117.         return results;  
  118.     }  
  119.   
  120.     public List  runSearch()  throws IOException {  
  121.         index();  
  122.         return search();  
  123.     }  
  124.   
  125.     public static void main(String[] args) throws Exception {  
  126.         System.out  
  127.                 .println("Facet counting over multiple category lists example:");  
  128.         System.out.println("-----------------------");  
  129.         List  results =  new MultiCategoryListsFacetsExample().runSearch();  
  130.         System.out.println("Author: " + results.get(0));  
  131.         System.out.println("Publish Date: " + results.get(1));  
  132.     }  
  133. }  

    上面说的Facet数字统计方式都是按照出现次数计算总和,其实lucene还提供了js表达式方式自定义Facet数据统计,比如: 

Java代码   收藏代码
  1. /**当前索引文档评分乘以popularity域值的平方根 作为 Facet的统计值,默认是统计命中索引文档总数*/  
  2. Expression expr = JavascriptCompiler.compile("_score * sqrt(popularity)");  

    即表示每个域的域值相同的落入一组,但此时每一组的数字总计不再是计算总个数,而是按照指定的js表达式去计算然后求和,比如上述表达式即表示当前索引文档评分乘以popularity域值的平方根 作为 Facet的统计值,_score是内置变量代指当前索引文档的评分,sqrt是内置函数表示开平方根,lucene expression表达式是通过JavascriptCompiler进行编译的,而JavascriptCompiler是借助大名鼎鼎的开源语法分析器antlr实现的,与antlr类似的还有JFlex,自己google了解去,关于语法分析这个话题就超出本篇主题了。下面说说lucene expression都支持哪些函数和操作符:

     大意就是它是基于JavaScript语法的特定数字表达式,它支持:

     1,Integer,float数字,十六进制和八进制字符

     2.支持常用的数学操作符,加减乘除取模等

     3.支持位运算符

     4.支持布尔运算符

     5.支持比较运算符

     6.支持常用的数学函数,比如abs取绝对值,log对数,max取最大值,sqrt开平方根等

     7.支持三角函数,比如sin,cos等等

     8.支持地理函数,如haversin公式即求地球上任意两个点之间的距离,具体请自己去Google haversin公式

     9.辅助函数,貌似跟第6条重复,搞什么飞机,我只是翻译下而已,跟我没关系

     10.支持任意的外部变量,这一条有点费解,还好我在源码里找到了相关说明

 

     查阅org.apache.lucene.expressions.js包下面的package.html,看到里面有这样一句提示:

       打开Bindings类源码,没看到什么有用的信息,然后我无意在JavascriptCompiler类源码中找到如下一段说明,让我茅塞顿开:

Html代码   收藏代码
  1. /**  
  2.  * An expression compiler for javascript expressions.  
  3.  * <p>  
  4.  * Example:  
  5.  * <pre class="prettyprint">  
  6.  *   Expression foo = JavascriptCompiler.compile("((0.3*popularity)/10.0)+(0.7*score)");  
  7.  *  pre>  
  8.  * <p>  
  9.  * See the {@link org.apache.lucene.expressions.js package documentation} for   
  10.  * the supported syntax and default functions.  
  11.  * <p>  
  12.  * You can compile with an alternate set of functions via {@link #compile(String, Map, ClassLoader)}.  
  13.  * For example:  
  14.  * <pre class="prettyprint">  
  15.  *   Map   functions =  new HashMap<>();  
  16.  *   // add all the default functions  
  17.  *   functions.putAll(JavascriptCompiler.DEFAULT_FUNCTIONS);  
  18.  *   // add cbrt()  
  19.  *   functions.put("cbrt", Math.class.getMethod("cbrt", double.class));  
  20.  *   // call compile with customized function map  
  21.  *   Expression foo = JavascriptCompiler.compile("cbrt(score)+ln(popularity)",   
  22.  *                                               functions,   
  23.  *                                               getClass().getClassLoader());  
  24.  *  pre>  
  25.  *   
  26.  * @lucene.experimental  
  27.  */  

    重点在这里:

Java代码   收藏代码
  1. Map  functions =  new HashMap ();  
  2.  // add all the default functions  
  3. functions.putAll(JavascriptCompiler.DEFAULT_FUNCTIONS);  
  4. // add cbrt()  
  5. functions.put("cbrt", Math.class.getMethod("cbrt", double.class));  
  6. // call compile with customized function map  
  7. Expression foo = JavascriptCompiler.compile("cbrt(score)+ln(popularity)",   
  8.                                              functions,   
  9.                                              getClass().getClassLoader());  

    通过示例代码,不难理解,意思就是我们可以把我们Java里类的某个方法通过JavascriptCompilter进行编译,就能像直接调用js内置函数一样,毕竟js内置函数是有限的,但内置的js函数不能满足你的要求,你就可以把java里自定义方法进行编译在js里执行。示例的代码就是把Math类里的cbrt方法(求一个double数值的立方根)编译为js内置函数,然后你就可以像使用js内置函数一样使用java里任意类的方法了。下面是一个使用lucene expressions完成Facet统计的完整示例:

Java代码   收藏代码
  1. package com.yida.framework.lucene5.facet;  
  2.   
  3. import java.io.IOException;  
  4. import java.text.ParseException;  
  5.   
  6. import org.apache.lucene.analysis.core.WhitespaceAnalyzer;  
  7. import org.apache.lucene.document.Document;  
  8. import org.apache.lucene.document.Field;  
  9. import org.apache.lucene.document.NumericDocValuesField;  
  10. import org.apache.lucene.document.TextField;  
  11. import org.apache.lucene.expressions.Expression;  
  12. import org.apache.lucene.expressions.SimpleBindings;  
  13. import org.apache.lucene.expressions.js.JavascriptCompiler;  
  14. import org.apache.lucene.facet.FacetField;  
  15. import org.apache.lucene.facet.FacetResult;  
  16. import org.apache.lucene.facet.Facets;  
  17. import org.apache.lucene.facet.FacetsCollector;  
  18. import org.apache.lucene.facet.FacetsConfig;  
  19. import org.apache.lucene.facet.taxonomy.TaxonomyFacetSumValueSource;  
  20. import org.apache.lucene.facet.taxonomy.TaxonomyReader;  
  21. import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;  
  22. import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter;  
  23. import org.apache.lucene.index.DirectoryReader;  
  24. import org.apache.lucene.index.IndexWriter;  
  25. import org.apache.lucene.index.IndexWriterConfig;  
  26. import org.apache.lucene.search.IndexSearcher;  
  27. import org.apache.lucene.search.MatchAllDocsQuery;  
  28. import org.apache.lucene.search.SortField;  
  29. import org.apache.lucene.store.Directory;  
  30. import org.apache.lucene.store.RAMDirectory;  
  31.   
  32. public class ExpressionAggregationFacetsExample {  
  33.     private final Directory indexDir = new RAMDirectory();  
  34.     private final Directory taxoDir = new RAMDirectory();  
  35.     private final FacetsConfig config = new FacetsConfig();  
  36.   
  37.     private void index() throws IOException {  
  38.         IndexWriter indexWriter = new IndexWriter(this.indexDir,  
  39.                 new IndexWriterConfig(new WhitespaceAnalyzer())  
  40.                         .setOpenMode(IndexWriterConfig.OpenMode.CREATE));  
  41.   
  42.         DirectoryTaxonomyWriter taxoWriter = new DirectoryTaxonomyWriter(  
  43.                 this.taxoDir);  
  44.   
  45.         Document doc = new Document();  
  46.         doc.add(new TextField("c", "foo bar", Field.Store.NO));  
  47.         doc.add(new NumericDocValuesField("popularity", 5L));  
  48.         doc.add(new FacetField("A", new String[] { "B" }));  
  49.         indexWriter.addDocument(this.config.build(taxoWriter, doc));  
  50.   
  51.         doc = new Document();  
  52.         doc.add(new TextField("c", "foo foo bar", Field.Store.NO));  
  53.         doc.add(new NumericDocValuesField("popularity", 3L));  
  54.         doc.add(new FacetField("A", new String[] { "C" }));  
  55.         indexWriter.addDocument(this.config.build(taxoWriter, doc));  
  56.           
  57.         doc = new Document();  
  58.         doc.add(new TextField("c", "foo foo bar", Field.Store.NO));  
  59.         doc.add(new NumericDocValuesField("popularity", 8L));  
  60.         doc.add(new FacetField("A", new String[] { "B" }));  
  61.         indexWriter.addDocument(this.config.build(taxoWriter, doc));  
  62.   
  63.         indexWriter.close();  
  64.         taxoWriter.close();  
  65.     }  
  66.   
  67.     private FacetResult search() throws IOException, ParseException {  
  68.         DirectoryReader indexReader = DirectoryReader.open(this.indexDir);  
  69.         IndexSearcher searcher = new IndexSearcher(indexReader);  
  70.         TaxonomyReader taxoReader = new DirectoryTaxonomyReader(this.taxoDir);  
  71.   
  72.         /**当前索引文档评分乘以popularity域值的平方根 作为 Facet的统计值,默认是统计命中索引文档总数*/  
  73.         Expression expr = JavascriptCompiler.compile("_score * sqrt(popularity)");  
  74.         SimpleBindings bindings = new SimpleBindings();  
  75.         bindings.add(new SortField("_score", SortField.Type.SCORE));  
  76.         bindings.add(new SortField("popularity", SortField.Type.LONG));  
  77.   
  78.         FacetsCollector fc = new FacetsCollector(true);  
  79.   
  80.         FacetsCollector.search(searcher, new MatchAllDocsQuery(), 10, fc);  
  81.   
  82.         //以Expression表达式的计算值定义一个Facet  
  83.         Facets facets = new TaxonomyFacetSumValueSource(taxoReader,  
  84.                 this.config, fc, expr.getValueSource(bindings));  
  85.         FacetResult result = facets.getTopChildren(10, "A", new String[0]);  
  86.   
  87.         indexReader.close();  
  88.         taxoReader.close();  
  89.   
  90.         return result;  
  91.     }  
  92.   
  93.     public FacetResult runSearch() throws IOException, ParseException {  
  94.         index();  
  95.         return search();  
  96.     }  
  97.   
  98.     public static void main(String[] args) throws Exception {  
  99.         System.out.println("Facet counting example:");  
  100.         System.out.println("-----------------------");  
  101.         FacetResult result = new ExpressionAggregationFacetsExample()  
  102.                 .runSearch();  
  103.         System.out.println(result);  
  104.     }  
  105. }  

    前面说到的Lucene Expression是通过一个表达式来计算统计值然后求和,我们也可以使用AssociationFacetField域来关联一个任意值,然后根据这个值来求和统计,类似这样:

Java代码   收藏代码
  1. //3 --> lucene[不再是统计lucene这个域值的出现总次数,而是统计IntAssociationFacetField的第一个构造参数assoc总和]  
  2. doc.add(new IntAssociationFacetField(3, "tags", new String[] { "lucene" }));  
  3. doc.add(new FloatAssociationFacetField(0.87F, "genre", new String[] { "computing" }));  

   其实创建一个AssociationFacetField等价于创建了一个StringField和一个BinaryDocValuesField(创建这个域是为了辅助统计Facet Count) ,有关AssociationFacetField的完整示例代码如下:

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.FacetResult;  
  11. import org.apache.lucene.facet.Facets;  
  12. import org.apache.lucene.facet.FacetsCollector;  
  13. import org.apache.lucene.facet.FacetsConfig;  
  14. import org.apache.lucene.facet.taxonomy.FloatAssociationFacetField;  
  15. import org.apache.lucene.facet.taxonomy.IntAssociationFacetField;  
  16. import org.apache.lucene.facet.taxonomy.TaxonomyFacetSumFloatAssociations;  
  17. import org.apache.lucene.facet.taxonomy.TaxonomyFacetSumIntAssociations;  
  18. import org.apache.lucene.facet.taxonomy.TaxonomyReader;  
  19. import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;  
  20. import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter;  
  21. import org.apache.lucene.index.DirectoryReader;  
  22. import org.apache.lucene.index.IndexWriter;  
  23. import org.apache.lucene.index.IndexWriterConfig;  
  24. import org.apache.lucene.search.IndexSearcher;  
  25. import org.apache.lucene.search.MatchAllDocsQuery;  
  26. import org.apache.lucene.store.Directory;  
  27. import org.apache.lucene.store.RAMDirectory;  
  28.   
  29. public class AssociationsFacetsExample {  
  30.     private final Directory indexDir = new RAMDirectory();  
  31.       private final Directory taxoDir = new RAMDirectory();  
  32.       private final FacetsConfig config;  
  33.   
  34.       public AssociationsFacetsExample()  
  35.       {  
  36.         this.config = new FacetsConfig();  
  37.         this.config.setMultiValued("tags", true);  
  38.         this.config.setIndexFieldName("tags", "$tags");  
  39.         this.config.setMultiValued("genre", true);  
  40.         this.config.setIndexFieldName("genre", "$genre");  
  41.       }  
  42.   
  43.       private void index() throws IOException  
  44.       {  
  45.         IndexWriterConfig iwc = new IndexWriterConfig(new WhitespaceAnalyzer()).setOpenMode(IndexWriterConfig.OpenMode.CREATE);  
  46.         IndexWriter indexWriter = new IndexWriter(this.indexDir, iwc);  
  47.   
  48.         DirectoryTaxonomyWriter taxoWriter = new DirectoryTaxonomyWriter(this.taxoDir);  
  49.   
  50.         Document doc = new Document();  
  51.   
  52.         //3 --> lucene[不再是统计lucene这个域值的出现总次数,而是统计IntAssociationFacetField的第一个构造参数assoc总和]  
  53.         doc.add(new IntAssociationFacetField(3, "tags", new String[] { "lucene" }));  
  54.   
  55.         doc.add(new FloatAssociationFacetField(0.87F, "genre", new String[] { "computing" }));  
  56.         indexWriter.addDocument(this.config.build(taxoWriter, doc));  
  57.   
  58.         doc = new Document();  
  59.   
  60.         //1 --> lucene  
  61.         doc.add(new IntAssociationFacetField(1, "tags", new String[] { "lucene" }));  
  62.   
  63.         doc.add(new IntAssociationFacetField(2, "tags", new String[] { "solr" }));  
  64.   
  65.         doc.add(new FloatAssociationFacetField(0.75F, "genre", new String[] { "computing" }));  
  66.   
  67.         doc.add(new FloatAssociationFacetField(0.34F, "genre", new String[] { "software" }));  
  68.         indexWriter.addDocument(this.config.build(taxoWriter, doc));  
  69.   
  70.         indexWriter.close();  
  71.         taxoWriter.close();  
  72.       }  
  73.   
  74.       private List  sumAssociations()  throws IOException  
  75.       {  
  76.         DirectoryReader indexReader = DirectoryReader.open(this.indexDir);  
  77.         IndexSearcher searcher = new IndexSearcher(indexReader);  
  78.         TaxonomyReader taxoReader = new DirectoryTaxonomyReader(this.taxoDir);  
  79.   
  80.         FacetsCollector fc = new FacetsCollector();  
  81.   
  82.         FacetsCollector.search(searcher, new MatchAllDocsQuery(), 10, fc);  
  83.   
  84.         //定义了两个Facet  
  85.         Facets tags = new TaxonomyFacetSumIntAssociations("$tags", taxoReader, this.config, fc);  
  86.         Facets genre = new TaxonomyFacetSumFloatAssociations("$genre", taxoReader, this.config, fc);  
  87.   
  88.         List  results =  new ArrayList ();  
  89.         results.add(tags.getTopChildren(10, "tags", new String[0]));  
  90.         results.add(genre.getTopChildren(10, "genre", new String[0]));  
  91.   
  92.         indexReader.close();  
  93.         taxoReader.close();  
  94.   
  95.         return results;  
  96.       }  
  97.   
  98.       private FacetResult drillDown() throws IOException  
  99.       {  
  100.         DirectoryReader indexReader = DirectoryReader.open(this.indexDir);  
  101.         IndexSearcher searcher = new IndexSearcher(indexReader);  
  102.         TaxonomyReader taxoReader = new DirectoryTaxonomyReader(this.taxoDir);  
  103.   
  104.         DrillDownQuery q = new DrillDownQuery(this.config);  
  105.   
  106.         q.add("tags", new String[] { "solr" });  
  107.         FacetsCollector fc = new FacetsCollector();  
  108.         FacetsCollector.search(searcher, q, 10, fc);  
  109.   
  110.         Facets facets = new TaxonomyFacetSumFloatAssociations("$genre", taxoReader, this.config, fc);  
  111.         FacetResult result = facets.getTopChildren(10, "$genre", new String[0]);  
  112.   
  113.         indexReader.close();  
  114.         taxoReader.close();  
  115.   
  116.         return result;  
  117.       }  
  118.   
  119.       public List  runSumAssociations()  throws IOException  
  120.       {  
  121.         index();  
  122.         return sumAssociations();  
  123.       }  
  124.   
  125.       public FacetResult runDrillDown() throws IOException  
  126.       {  
  127.         index();  
  128.         return drillDown();  
  129.       }  
  130.   
  131.       public static void main(String[] args) throws Exception  
  132.       {  
  133.         System.out.println("Sum associations example:");  
  134.         System.out.println("-------------------------");  
  135.         List  results =  new AssociationsFacetsExample().runSumAssociations();  
  136.         System.out.println("tags: " + results.get(0));  
  137.         System.out.println("genre: " + results.get(1));  
  138.       }  
  139. }  

    

      Facet就说这么多了,一些细节方面大家请看demo代码里面的注释,如果我哪里没说到的而你又感觉很迷惑无法理解的,请提出来,大家一起交流学习。如果我有哪里说的不够准确,也希望大家能够积极指正多多批评。 Demo源码请看底下的附件!!!

相关实践学习
【玩转ComfyUI】基于函数计算一键部署AI生图平台ComfyUI
本次实验将带大家通过使用阿里云产品函数计算FC,快速使用ComfyUI实现更高质量的图像生成。
从 0 入门函数计算
在函数计算的架构中,开发者只需要编写业务代码,并监控业务运行情况就可以了。这将开发者从繁重的运维工作中解放出来,将精力投入到更有意义的开发任务上。
目录
相关文章
|
C语言
C语言栈的括号匹配的检验讲解及相关代码
C语言栈的括号匹配的检验讲解及相关代码
666 0
|
存储 算法 数据库
一起聊聊图像质量和美学评估的数据集
图像质量和美学评估是计算机视觉领域中热点的研究问题,并且极具应用前景,可与众多实际应用深度结合。评价一张图片,主要从两个方向,一个是图像的质量,如像素、清晰度、有无噪声等,一个是图像的感觉,也就是美学,如构图、颜色、内容主体等。通过这两个方面就可以评价一张图片的好坏,通过计算机视觉算法,可以为图片自动评分,得分高的图片被认为较好,可以用于推荐和搜索等应用场景。本文主要聊聊一些关于图像质量和美学评估
14766 1
|
8月前
|
人工智能 监控 区块链
保姆级图文教学!OpenClaw(Clawdbot)阿里云/本地部署+7大场景70个真实案例 效率翻倍指南
OpenClaw(原Clawdbot、Moltbot)的爆火,不在于其基础的对话能力,而在于它“自主执行任务”的核心特性——通过70个经过社区验证的真实案例,覆盖内容创作、记忆管理、夜间自动化、金融监控等8大核心场景,真正实现“你睡觉、AI干活”的高效模式。无论是医生将医学通讯转为通勤播客,还是开发者让AI夜间清理GitHub过期Issue,OpenClaw都在通过场景化落地,重新定义AI助手的价值。
1122 4
保姆级图文教学!OpenClaw(Clawdbot)阿里云/本地部署+7大场景70个真实案例 效率翻倍指南
|
8月前
|
存储 监控 前端开发
分布式系统异常架构级设计:根治线上故障的全链路规范与落地实践
本文基于Java 21、Spring Boot 3.4.2等最新技术栈,系统阐述分布式异常体系的架构级设计:涵盖本质挑战、分层职责(接入层/业务层/数据层/基础设施层)、自定义异常规范、错误码设计、全链路traceId传递、异步与Feign异常处理、熔断隔离及监控告警闭环,助力故障排查从小时级降至分钟级。
542 1
|
6月前
|
人工智能 数据库 知识图谱
RAG检索增强生成
本节详解RAG(检索增强生成)技术:通过“先检索、再生成”解决大模型知识过时、缺乏私有知识和幻觉三大痛点;涵盖完整架构、分块策略、Naive/Advanced/Graph RAG演进、评估方法及实战代码,助你构建可靠私有知识问答系统。
751 1
|
9月前
|
人工智能 JSON 自然语言处理
想让大模型更懂你?从原理到实践,详解高效微调的全流程
本文深入解析大模型微调中的核心参数调优与显存优化策略,涵盖学习率、训练轮数、批量大小、截断长度、LoRA秩五大关键参数的原理、调参技巧及显存影响,并结合LLaMA-Factory实战演示高效微调全流程,助你低成本、高质地打造专属AI助手。(239字)
909 1
|
9月前
|
数据采集 存储 人工智能
企业建设数据治理系统费用(2026年2月最新)
截至2026年,中国企业数据治理投入显著增长:2025年总支出287亿元,预计2026年超340亿元(+18.5%)。大型企业单项目平均投入860万元,中小企业多选SaaS方案(30–60万元/年)。合规驱动下,71%中企已将数据治理纳入核心IT战略。
|
9月前
|
机器学习/深度学习 算法 安全
【PINN回归预测】基于遗传优化算法GA改进物理信息神经网络(PINN)的多变量回归预测模型附Matlab代码
✅作者简介:热爱科研的Matlab仿真开发者,擅长 毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真 。 🍎 往期回顾关注个人主页: Matlab科研工作室  👇 关注我领取海量matlab电子书和数学建模资料  🍊个人信条:格物致知, 完整Matlab代码获取及仿真咨询内容私信 。 🔥  内容介绍  一、研究背景与问题提出 在复杂工业系统(如化工反应过程、能源动力系统)、工程物理过程(如桥梁结构应力分析)及环境监测领域,多变量回归预测是核心任务。传统数据驱动模型(如BP神经网络、随机森林)依赖大规模标注数据,但存在两大缺陷:一是缺乏对系统内在物理
484 1
|
11月前
|
人工智能 自然语言处理 机器人
教学场景机器人关键技术解析与主流产品选型指南
随着AI技术深入教育,教学机器人正从展示工具进化为集辅导、减负、管理于一体的“认知伙伴”。依托NLP、CV、SLAM等技术,结合神经符号引擎、多模态情感计算与联邦学习,实现精准教学与隐私保护。猎户星空、优必选、科大讯飞、大疆等企业各具优势,推动教育智能化迈向新阶段。(238字)
806 6
|
11月前
|
搜索推荐
掌握三大核心技巧,快速成为1688运营高手!
1688运营需聚焦三大核心:提升店铺综合权重、优化搜索相关性、挖掘流量价值。通过商品、转化、服务等多维度协同,精准匹配关键词与类目,强化客户体验与复购,系统提升L等级与动销表现,实现曝光、转化双增长。每月复盘,稳步推进,打造高竞争力店铺。

热门文章

最新文章