Lucene5学习之Group分组统计

 Group即分组,类似SQL里的group by功能,Lucene中分组是通过内置的几种Collector结果集收集器实现的,有关group的结果集收集器都在org.apache.lucene.search.grouping包及其子包下,

 包含group关键字的Collector都是有关Group分组的结果收集器,如果你只需要统计如下这些分组信息:

Java代码  

  1. /** 所有组的数量 */  
  2. int totalGroupCount = 0;  
  3. /** 所有满足条件的记录数 */  
  4. int totalHitCount = 0;  
  5. /** 所有组内的满足条件的记录数(通常该值与totalHitCount是一致的) */  
  6. int totalGroupedHitCount = -1;  

   则直接使用FirstPassGroupingCollector收集器即可,如果你需要统计每个分组内部的命中总数以及命中索引文档的评分等信息,则需要使用SecondPassGroupingCollector,为了提高第二次查询的效率,你可以使用CacheCollector来缓存第一次查询结果,这样第二次就直接从缓存中获取第一次查询结果,为了统计总的分组数量,你可能还需要使用AllGroupsCollector结果收集器。常用的结果收集器就这几个。

    下面是一个Group分组使用示例,具体详细说明请看代码里面的注释:

Java代码  

  1. package com.yida.framework.lucene5.group;  
  2.   
  3. import java.io.IOException;  
  4. import java.nio.file.Paths;  
  5. import java.util.ArrayList;  
  6. import java.util.Collection;  
  7. import java.util.HashMap;  
  8. import java.util.Iterator;  
  9. import java.util.List;  
  10. import java.util.Random;  
  11.   
  12. import org.apache.lucene.analysis.Analyzer;  
  13. import org.apache.lucene.analysis.standard.StandardAnalyzer;  
  14. import org.apache.lucene.document.Document;  
  15. import org.apache.lucene.document.Field;  
  16. import org.apache.lucene.document.Field.Index;  
  17. import org.apache.lucene.document.Field.Store;  
  18. import org.apache.lucene.document.SortedDocValuesField;  
  19. import org.apache.lucene.document.TextField;  
  20. import org.apache.lucene.index.DirectoryReader;  
  21. import org.apache.lucene.index.IndexReader;  
  22. import org.apache.lucene.index.IndexWriter;  
  23. import org.apache.lucene.index.IndexWriterConfig;  
  24. import org.apache.lucene.index.IndexWriterConfig.OpenMode;  
  25. import org.apache.lucene.index.Term;  
  26. import org.apache.lucene.queries.function.ValueSource;  
  27. import org.apache.lucene.queries.function.valuesource.BytesRefFieldSource;  
  28. import org.apache.lucene.search.CachingCollector;  
  29. import org.apache.lucene.search.Collector;  
  30. import org.apache.lucene.search.IndexSearcher;  
  31. import org.apache.lucene.search.MultiCollector;  
  32. import org.apache.lucene.search.Query;  
  33. import org.apache.lucene.search.ScoreDoc;  
  34. import org.apache.lucene.search.SimpleCollector;  
  35. import org.apache.lucene.search.Sort;  
  36. import org.apache.lucene.search.TermQuery;  
  37. import org.apache.lucene.search.grouping.AbstractAllGroupsCollector;  
  38. import org.apache.lucene.search.grouping.AbstractFirstPassGroupingCollector;  
  39. import org.apache.lucene.search.grouping.AbstractSecondPassGroupingCollector;  
  40. import org.apache.lucene.search.grouping.GroupDocs;  
  41. import org.apache.lucene.search.grouping.SearchGroup;  
  42. import org.apache.lucene.search.grouping.TopGroups;  
  43. import org.apache.lucene.search.grouping.function.FunctionAllGroupsCollector;  
  44. import org.apache.lucene.search.grouping.function.FunctionFirstPassGroupingCollector;  
  45. import org.apache.lucene.search.grouping.function.FunctionSecondPassGroupingCollector;  
  46. import org.apache.lucene.search.grouping.term.TermAllGroupsCollector;  
  47. import org.apache.lucene.search.grouping.term.TermFirstPassGroupingCollector;  
  48. import org.apache.lucene.search.grouping.term.TermSecondPassGroupingCollector;  
  49. import org.apache.lucene.store.Directory;  
  50. import org.apache.lucene.store.FSDirectory;  
  51. import org.apache.lucene.util.BytesRef;  
  52. import org.apache.lucene.util.mutable.MutableValue;  
  53. import org.apache.lucene.util.mutable.MutableValueStr;  
  54.   
  55. import com.yida.framework.lucene5.util.Tools;  
  56. /** 
  57.  * Lucene分组测试 
  58.  * @author Lanxiaowei 
  59.  * 
  60.  */  
  61. public class GroupTest {  
  62.     /** 索引目录 */  
  63.     private static final String indexDir = "C:/group-index";  
  64.     /** 分词器 */  
  65.     private static Analyzer analyzer = new StandardAnalyzer();  
  66.     /** 分组域 */  
  67.     private static String groupField = "author";  
  68.   
  69.     public static void main(String[] args) throws Exception {  
  70.         // 创建测试索引  
  71.         // createIndex();  
  72.         Directory directory = FSDirectory.open(Paths.get(indexDir));  
  73.         IndexReader reader = DirectoryReader.open(directory);  
  74.         IndexSearcher searcher = new IndexSearcher(reader);  
  75.         Query query = new TermQuery(new Term("content", "random"));  
  76.         /**每个分组内部的排序规则*/  
  77.         Sort groupSort = Sort.RELEVANCE;  
  78.         groupBy(searcher, query, groupSort);  
  79.         //groupSearch(searcher);  
  80.     }  
  81.   
  82.     public static void groupBy(IndexSearcher searcher, Query query, Sort groupSort)  
  83.             throws IOException {  
  84.         /** 前N条中分组 */  
  85.         int topNGroups = 10;  
  86.         /** 分组起始偏移量 */  
  87.         int groupOffset = 0;  
  88.         /** 是否填充SearchGroup的sortValues */  
  89.         boolean fillFields = true;  
  90.         /** groupSort用于对组进行排序,docSort用于对组内记录进行排序,多数情况下两者是相同的,但也可不同 */  
  91.         Sort docSort = groupSort;  
  92.         /** 用于组内分页,起始偏移量 */  
  93.         int docOffset = 0;  
  94.         /** 每组返回多少条结果 */  
  95.         int docsPerGroup = 2;  
  96.         /** 是否需要计算总的分组数量 */  
  97.         boolean requiredTotalGroupCount = true;  
  98.         /** 是否需要缓存评分 */  
  99.         boolean cacheScores = true;  
  100.   
  101.         TermFirstPassGroupingCollector c1 = new TermFirstPassGroupingCollector(  
  102.                 "author", groupSort, groupOffset + topNGroups);  
  103.         //第一次查询缓存容量的大小:设置为16M  
  104.         double maxCacheRAMMB = 16.0;  
  105.         /** 将TermFirstPassGroupingCollector包装成CachingCollector,为第一次查询加缓存,避免重复评分  
  106.          *  CachingCollector就是用来为结果收集器添加缓存功能的 
  107.          */  
  108.         CachingCollector cachedCollector = CachingCollector.create(c1,  
  109.                 cacheScores, maxCacheRAMMB);  
  110.         // 开始第一次分组统计  
  111.         searcher.search(query, cachedCollector);  
  112.   
  113.         /**第一次查询返回的结果集TopGroups中只有分组域值以及每组总的评分,至于每个分组里有几条,分别哪些索引文档,则需要进行第二次查询获取*/  
  114.         Collection<SearchGroup<BytesRef>> topGroups = c1.getTopGroups(  
  115.                 groupOffset, fillFields);  
  116.   
  117.         if (topGroups == null) {  
  118.             System.out.println("No groups matched ");  
  119.             return;  
  120.         }  
  121.           
  122.         Collector secondPassCollector = null;  
  123.           
  124.         // 是否获取每个分组内部每个索引的评分  
  125.         boolean getScores = true;  
  126.         // 是否计算最大评分  
  127.         boolean getMaxScores = true;  
  128.         // 如果需要对Lucene的score进行修正,则需要重载TermSecondPassGroupingCollector  
  129.         TermSecondPassGroupingCollector c2 = new TermSecondPassGroupingCollector(  
  130.                 "author", topGroups, groupSort, docSort, docOffset  
  131.                         + docsPerGroup, getScores, getMaxScores, fillFields);  
  132.   
  133.         // 如果需要计算总的分组数量,则需要把TermSecondPassGroupingCollector包装成TermAllGroupsCollector  
  134.         // TermAllGroupsCollector就是用来收集总分组数量的  
  135.         TermAllGroupsCollector allGroupsCollector = null;  
  136.         //若需要统计总的分组数量  
  137.         if (requiredTotalGroupCount) {  
  138.             allGroupsCollector = new TermAllGroupsCollector("author");  
  139.             secondPassCollector = MultiCollector.wrap(c2, allGroupsCollector);  
  140.         } else {  
  141.             secondPassCollector = c2;  
  142.         }  
  143.   
  144.         /**如果第一次查询已经加了缓存,则直接从缓存中取*/  
  145.         if (cachedCollector.isCached()) {  
  146.             // 第二次查询直接从缓存中取  
  147.             cachedCollector.replay(secondPassCollector);  
  148.         } else {  
  149.             // 开始第二次分组查询  
  150.             searcher.search(query, secondPassCollector);  
  151.         }  
  152.   
  153.         /** 所有组的数量 */  
  154.         int totalGroupCount = 0;  
  155.         /** 所有满足条件的记录数 */  
  156.         int totalHitCount = 0;  
  157.         /** 所有组内的满足条件的记录数(通常该值与totalHitCount是一致的) */  
  158.         int totalGroupedHitCount = -1;  
  159.         if (requiredTotalGroupCount) {  
  160.             totalGroupCount = allGroupsCollector.getGroupCount();  
  161.         }  
  162.         //打印总的分组数量  
  163.         System.out.println("groupCount: " + totalGroupCount);  
  164.   
  165.         TopGroups<BytesRef> groupsResult = c2.getTopGroups(docOffset);  
  166.         //这里打印的3项信息就是第一次查询的统计结果  
  167.         totalHitCount = groupsResult.totalHitCount;  
  168.         totalGroupedHitCount = groupsResult.totalGroupedHitCount;  
  169.         System.out.println("groupsResult.totalHitCount:" + totalHitCount);  
  170.         System.out.println("groupsResult.totalGroupedHitCount:"  
  171.                 + totalGroupedHitCount);  
  172.         System.out.println("///////////////////////////////////////////////");  
  173.         int groupIdx = 0;  
  174.           
  175.         //下面打印的是第二次查询的统计结果,如果你仅仅值需要第一次查询的统计结果信息,不需要每个分组内部的详细信息,则不需要进行第二次查询,请知晓  
  176.         // 迭代组  
  177.         for (GroupDocs<BytesRef> groupDocs : groupsResult.groups) {  
  178.             groupIdx++;  
  179.             String groupVL = groupDocs.groupValue == null ? "分组域的域值为空" : new String(groupDocs.groupValue.bytes);  
  180.             // 分组域的域值,groupIdx表示组的索引即第几组  
  181.             System.out.println("group[" + groupIdx + "].groupFieldValue:" + groupVL);  
  182.             // 当前分组内命中的总记录数  
  183.             System.out  
  184.                     .println("group[" + groupIdx + "].totalHits:" + groupDocs.totalHits);  
  185.             int docIdx = 0;  
  186.             // 迭代组内的记录  
  187.             for (ScoreDoc scoreDoc : groupDocs.scoreDocs) {  
  188.                 docIdx++;  
  189.                 // 打印分组内部每条记录的索引文档ID及其评分  
  190.                 System.out.println("group[" + groupIdx + "][" + docIdx + "]{docID:Score}:"  
  191.                         + scoreDoc.doc + "/" + scoreDoc.score);  
  192.                 //根据docID可以获取到整个Document对象,通过doc.get(fieldName)可以获取某个存储域的域值  
  193.                 //注意searcher.doc根据docID返回的document对象中不包含docValuesField域的域值,只包含非docValuesField域的域值,请知晓  
  194.                 Document doc = searcher.doc(scoreDoc.doc);  
  195.                 System.out.println("group[" + groupIdx + "][" + docIdx + "]{docID:author}:"  
  196.                         + doc.get("id") + ":" + doc.get("content"));  
  197.             }  
  198.             System.out.println("******************华丽且拉轰的分割线***********************");  
  199.         }  
  200.     }  
  201.   
  202.     public static void groupSearch(IndexSearcher indexSearcher)  
  203.             throws IOException {  
  204.   
  205.         Sort groupSort = Sort.RELEVANCE;  
  206.   
  207.         /** 第一次查询只有Top N条记录进行分组统计 */  
  208.         final AbstractFirstPassGroupingCollector<?> c1 = createRandomFirstPassCollector(  
  209.                 groupField, groupSort, 10);  
  210.         indexSearcher.search(new TermQuery(new Term("content", "random")), c1);  
  211.   
  212.         /* 
  213.          * final AbstractSecondPassGroupingCollector<?> c2 = 
  214.          * createSecondPassCollector( c1, groupField, groupSort, null, 0, 5, 
  215.          * true, true, true); indexSearcher.search(new TermQuery(new 
  216.          * Term("content", "random")), c2); 
  217.          */  
  218.   
  219.         /** 第一个参数表示截取偏移量offset,截取[offset, offset+topN]范围内的组 */  
  220.         Collection<?> groups = c1.getTopGroups(0, true);  
  221.         System.out.println("group.size:" + groups.size());  
  222.         for (Object object : groups) {  
  223.             SearchGroup searchGroup = (SearchGroup) object;  
  224.   
  225.             if (searchGroup.groupValue != null) {  
  226.                 if (searchGroup.groupValue.getClass().isAssignableFrom(  
  227.                         BytesRef.class)) {  
  228.                     String groupVL = new String(  
  229.                             (((BytesRef) searchGroup.groupValue)).bytes);  
  230.                     if (groupVL.equals("")) {  
  231.                         System.out.println("该分组不包含分组域");  
  232.                     } else {  
  233.                         System.out.println(groupVL);  
  234.                     }  
  235.                 } else if (searchGroup.groupValue.getClass().isAssignableFrom(  
  236.                         MutableValueStr.class)) {  
  237.                     if (searchGroup.groupValue.toString().endsWith("(null)")) {  
  238.                         System.out.println("该分组不包含分组域");  
  239.                     } else {  
  240.                         System.out  
  241.                                 .println(new String(  
  242.                                         (((MutableValueStr) searchGroup.groupValue)).value  
  243.                                                 .bytes()));  
  244.                     }  
  245.                 }  
  246.             } else {  
  247.                 System.out.println("该分组不包含分组域");  
  248.             }  
  249.             for (int i = 0; i < searchGroup.sortValues.length; i++) {  
  250.                 System.out.println("searchGroup.sortValues:"  
  251.                         + searchGroup.sortValues[i]);  
  252.             }  
  253.         }  
  254.   
  255.         /* 
  256.          * System.out.println("groups.maxScore:" + groups.maxScore); 
  257.          * System.out.println("groups.totalHitCount:" + groups.totalHitCount); 
  258.          * System.out.println("groups.totalGroupedHitCount:" + 
  259.          * groups.totalGroupedHitCount); System.out.println("groups.length:" + 
  260.          * groups.groups.length); System.out.println(""); 
  261.          *  
  262.          * GroupDocs<?> group = groups.groups[0]; compareGroupValue("author3", 
  263.          * group); System.out.println(group.scoreDocs.length); 
  264.          */  
  265.   
  266.     }  
  267.   
  268.     /** 
  269.      * 创建测试用的索引文档 
  270.      *  
  271.      * @throws IOException 
  272.      */  
  273.     public static void createIndex() throws IOException {  
  274.         Directory dir = FSDirectory.open(Paths.get(indexDir));  
  275.         IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);  
  276.         indexWriterConfig.setOpenMode(OpenMode.CREATE_OR_APPEND);  
  277.         IndexWriter writer = new IndexWriter(dir, indexWriterConfig);  
  278.         addDocuments(groupField, writer);  
  279.     }  
  280.   
  281.     /** 
  282.      * 添加索引文档 
  283.      *  
  284.      * @param groupField 
  285.      * @param writer 
  286.      * @throws IOException 
  287.      */  
  288.     public static void addDocuments(String groupField, IndexWriter writer)  
  289.             throws IOException {  
  290.         // 0  
  291.         Document doc = new Document();  
  292.         addGroupField(doc, groupField, "author1");  
  293.         doc.add(new TextField("content", "random text", Field.Store.YES));  
  294.         doc.add(new Field("id", "1", Store.YES, Index.NOT_ANALYZED));  
  295.         writer.addDocument(doc);  
  296.   
  297.         // 1  
  298.         doc = new Document();  
  299.         addGroupField(doc, groupField, "author1");  
  300.         doc.add(new TextField("content", "some more random text",  
  301.                 Field.Store.YES));  
  302.         doc.add(new Field("id", "2", Store.YES, Index.NOT_ANALYZED));  
  303.         writer.addDocument(doc);  
  304.   
  305.         // 2  
  306.         doc = new Document();  
  307.         addGroupField(doc, groupField, "author1");  
  308.         doc.add(new TextField("content", "some more random textual data",  
  309.                 Field.Store.YES));  
  310.         doc.add(new Field("id", "3", Store.YES, Index.NOT_ANALYZED));  
  311.         writer.addDocument(doc);  
  312.   
  313.         // 3  
  314.         doc = new Document();  
  315.         addGroupField(doc, groupField, "author2");  
  316.         doc.add(new TextField("content", "some random text", Field.Store.YES));  
  317.         doc.add(new Field("id", "4", Store.YES, Index.NOT_ANALYZED));  
  318.         writer.addDocument(doc);  
  319.   
  320.         // 4  
  321.         doc = new Document();  
  322.         addGroupField(doc, groupField, "author3");  
  323.         doc.add(new TextField("content", "some more random text",  
  324.                 Field.Store.YES));  
  325.         doc.add(new Field("id", "5", Store.YES, Index.NOT_ANALYZED));  
  326.         writer.addDocument(doc);  
  327.   
  328.         // 5  
  329.         doc = new Document();  
  330.         addGroupField(doc, groupField, "author3");  
  331.         doc.add(new TextField("content", "random", Field.Store.YES));  
  332.         doc.add(new Field("id", "6", Store.YES, Index.NOT_ANALYZED));  
  333.         writer.addDocument(doc);  
  334.   
  335.         // 6 -- no author field  
  336.         doc = new Document();  
  337.         doc.add(new TextField("content",  
  338.                 "random word stuck in alot of other text", Field.Store.YES));  
  339.         doc.add(new Field("id", "6", Store.YES, Index.NOT_ANALYZED));  
  340.         writer.addDocument(doc);  
  341.         writer.commit();  
  342.         writer.close();  
  343.     }  
  344.   
  345.     /** 
  346.      * 判断域值是否与分组域值相等 
  347.      *  
  348.      * @param expected 
  349.      * @param group 
  350.      */  
  351.     private static void compareGroupValue(String expected, GroupDocs<?> group) {  
  352.         if (expected == null) {  
  353.             if (group.groupValue == null) {  
  354.                 return;  
  355.             } else if (group.groupValue.getClass().isAssignableFrom(  
  356.                     MutableValueStr.class)) {  
  357.                 return;  
  358.             } else if (((BytesRef) group.groupValue).length == 0) {  
  359.                 return;  
  360.             }  
  361.         }  
  362.   
  363.         if (group.groupValue.getClass().isAssignableFrom(BytesRef.class)) {  
  364.             System.out.println("expected == groupValue?"  
  365.                     + new BytesRef(expected) == group.groupValue);  
  366.         } else if (group.groupValue.getClass().isAssignableFrom(  
  367.                 MutableValueStr.class)) {  
  368.             MutableValueStr v = new MutableValueStr();  
  369.             v.value.copyChars(expected);  
  370.             System.out  
  371.                     .println("expected == groupValue?" + v == group.groupValue);  
  372.         } else {  
  373.         }  
  374.     }  
  375.   
  376.     /** 
  377.      * 创建FirstPassCollector首次检索 
  378.      *  
  379.      * @param groupField 
  380.      * @param groupSort 
  381.      * @param topDocs 
  382.      * @param firstPassGroupingCollector 
  383.      * @return 
  384.      * @throws IOException 
  385.      */  
  386.     private AbstractFirstPassGroupingCollector<?> createFirstPassCollector(  
  387.             String groupField, Sort groupSort, int topDocs,  
  388.             AbstractFirstPassGroupingCollector<?> firstPassGroupingCollector)  
  389.             throws IOException {  
  390.         if (TermFirstPassGroupingCollector.class  
  391.                 .isAssignableFrom(firstPassGroupingCollector.getClass())) {  
  392.             ValueSource vs = new BytesRefFieldSource(groupField);  
  393.             return new FunctionFirstPassGroupingCollector(vs, new HashMap(),  
  394.                     groupSort, topDocs);  
  395.         }  
  396.         return new TermFirstPassGroupingCollector(groupField, groupSort,  
  397.                 topDocs);  
  398.     }  
  399.   
  400.     private static AbstractFirstPassGroupingCollector<?> createRandomFirstPassCollector(  
  401.             String groupField, Sort groupSort, int topDocs) throws IOException {  
  402.         AbstractFirstPassGroupingCollector<?> selected;  
  403.         // boolean flag = new Random().nextBoolean();  
  404.         if (false) {  
  405.             ValueSource vs = new BytesRefFieldSource(groupField);  
  406.             // FunctionFirstPassGroupingCollector区别是对于分组域的值采用MutableValueStr进行存储,  
  407.             // MutableValueStr内部维护的是一个BytesRefBuilder,BytesRefBuilder内部有一个grow函数,会自动  
  408.             // 扩充内部byte[]容量,而BytesRef是定长的buffer  
  409.             selected = new FunctionFirstPassGroupingCollector(vs,  
  410.                     new HashMap(), groupSort, topDocs);  
  411.         } else {  
  412.             // TermFirstPassGroupingCollector适用于你的分组域是一个非DocValuesField  
  413.             selected = new TermFirstPassGroupingCollector(groupField,  
  414.                     groupSort, topDocs);  
  415.         }  
  416.         return selected;  
  417.     }  
  418.   
  419.     private static <T> AbstractSecondPassGroupingCollector<T> createSecondPassCollector(  
  420.             AbstractFirstPassGroupingCollector firstPassGroupingCollector,  
  421.             String groupField, Sort groupSort, Sort sortWithinGroup,  
  422.             int groupOffset, int maxDocsPerGroup, boolean getScores,  
  423.             boolean getMaxScores, boolean fillSortFields) throws IOException {  
  424.   
  425.         if (TermFirstPassGroupingCollector.class  
  426.                 .isAssignableFrom(firstPassGroupingCollector.getClass())) {  
  427.             Collection<SearchGroup<BytesRef>> searchGroups = firstPassGroupingCollector  
  428.                     .getTopGroups(groupOffset, fillSortFields);  
  429.             return (AbstractSecondPassGroupingCollector) new TermSecondPassGroupingCollector(  
  430.                     groupField, searchGroups, groupSort, sortWithinGroup,  
  431.                     maxDocsPerGroup, getScores, getMaxScores, fillSortFields);  
  432.         } else {  
  433.             ValueSource vs = new BytesRefFieldSource(groupField);  
  434.             Collection<SearchGroup<MutableValue>> searchGroups = firstPassGroupingCollector  
  435.                     .getTopGroups(groupOffset, fillSortFields);  
  436.             return (AbstractSecondPassGroupingCollector) new FunctionSecondPassGroupingCollector(  
  437.                     searchGroups, groupSort, sortWithinGroup, maxDocsPerGroup,  
  438.                     getScores, getMaxScores, fillSortFields, vs, new HashMap());  
  439.         }  
  440.     }  
  441.   
  442.     // Basically converts searchGroups from MutableValue to BytesRef if grouping  
  443.     // by ValueSource  
  444.     @SuppressWarnings("unchecked")  
  445.     private AbstractSecondPassGroupingCollector<?> createSecondPassCollector(  
  446.             AbstractFirstPassGroupingCollector<?> firstPassGroupingCollector,  
  447.             String groupField, Collection<SearchGroup<BytesRef>> searchGroups,  
  448.             Sort groupSort, Sort sortWithinGroup, int maxDocsPerGroup,  
  449.             boolean getScores, boolean getMaxScores, boolean fillSortFields)  
  450.             throws IOException {  
  451.         if (firstPassGroupingCollector.getClass().isAssignableFrom(  
  452.                 TermFirstPassGroupingCollector.class)) {  
  453.             return new TermSecondPassGroupingCollector(groupField,  
  454.                     searchGroups, groupSort, sortWithinGroup, maxDocsPerGroup,  
  455.                     getScores, getMaxScores, fillSortFields);  
  456.         } else {  
  457.             ValueSource vs = new BytesRefFieldSource(groupField);  
  458.             List<SearchGroup<MutableValue>> mvalSearchGroups = new ArrayList<SearchGroup<MutableValue>>(  
  459.                     searchGroups.size());  
  460.             for (SearchGroup<BytesRef> mergedTopGroup : searchGroups) {  
  461.                 SearchGroup<MutableValue> sg = new SearchGroup();  
  462.                 MutableValueStr groupValue = new MutableValueStr();  
  463.                 if (mergedTopGroup.groupValue != null) {  
  464.                     groupValue.value.copyBytes(mergedTopGroup.groupValue);  
  465.                 } else {  
  466.                     groupValue.exists = false;  
  467.                 }  
  468.                 sg.groupValue = groupValue;  
  469.                 sg.sortValues = mergedTopGroup.sortValues;  
  470.                 mvalSearchGroups.add(sg);  
  471.             }  
  472.   
  473.             return new FunctionSecondPassGroupingCollector(mvalSearchGroups,  
  474.                     groupSort, sortWithinGroup, maxDocsPerGroup, getScores,  
  475.                     getMaxScores, fillSortFields, vs, new HashMap());  
  476.         }  
  477.     }  
  478.   
  479.     private AbstractAllGroupsCollector<?> createAllGroupsCollector(  
  480.             AbstractFirstPassGroupingCollector<?> firstPassGroupingCollector,  
  481.             String groupField) {  
  482.         if (firstPassGroupingCollector.getClass().isAssignableFrom(  
  483.                 TermFirstPassGroupingCollector.class)) {  
  484.             return new TermAllGroupsCollector(groupField);  
  485.         } else {  
  486.             ValueSource vs = new BytesRefFieldSource(groupField);  
  487.             return new FunctionAllGroupsCollector(vs, new HashMap());  
  488.         }  
  489.     }  
  490.   
  491.     /** 
  492.      * 添加分组域 
  493.      *  
  494.      * @param doc 
  495.      *            索引文档 
  496.      * @param groupField 
  497.      *            需要分组的域名称 
  498.      * @param value 
  499.      *            域值 
  500.      */  
  501.     private static void addGroupField(Document doc, String groupField,  
  502.             String value) {  
  503.         doc.add(new SortedDocValuesField(groupField, new BytesRef(value)));  
  504.     }  
  505. }  

    最近本人身体出了点小状况,人不太舒服,就不多说了,大家看看示例代码自己理解理解,里面注释我写的很详细了,如果你们有哪里看不懂,QQ上联系我。Demo源码在底下的附件里,请知晓!

 

    若你还有什么疑问,请加我Q-Q:7-3-6-0-3-1-3-0-5,或者加裙:

,欢迎你加入一起交流学习。

转载:http://iamyida.iteye.com/blog/2202651

时间: 2024-11-05 12:30:22

Lucene5学习之Group分组统计的相关文章

mongodb命令行group分组和java代码中group分组

group分组统计是数据库比较常用的功能,mongodb也不例外.不过相对于普通的增删改查,group操作就略微麻烦一些, 这里对group在shell中的操作.使用java原生代码操作以及集成spring进行操作进行一个简单的归纳总结,分组的途径和方法应该都有多种,这里每一样只举一例. 本例中数据源如下: 需要使用group实现的目的是:按年龄分组统计出每一组的数量. 1.mongo shell中执行如下命令: db.test.group({ key:{"age":1}, initi

分组统计方法:用Group By

分组|统计 原贴:http://community.csdn.net/Expert/topic/3739/3739565.xml?temp=.7632105表中三个字段|---------------------------------------------||  产品             数量                单价  ||=============================================||  A                3          

Lucene5学习之Facet简单入门

    说到Facet,我还真找不到一个合适的中文词汇来描述它,英文翻译是方面,感觉不够贴切,大家也不必纠结它的中文叫法是啥,你只需要知道使用Facet能解决什么类型的问题就行了,来看几个典型的应用案例:             看了上面几张图,大家应该知道Facet是用来干嘛的了,如果非要用语言描述Facet的用途,那Facet的用途就是根据域的域值进行分组统计,注意这里的域必须是FacetField,你Facet域的域值有几个就会分几组,并统计在Query查询条件下各组的命中结果数量.但通常

MYSQL每隔10分钟进行分组统计的实现方法_Mysql

前言 本文的内容主要是介绍了MYSQL每隔10分钟进行分组统计的实现方法,在画用户登录.操作情况在一天内的分布图时会非常有用,之前我只知道用「存储过程」实现的方法(虽然执行速度快,但真的是太不灵活了),后来学会了用高级点的「group by」方法来灵活实现类似功能. 正文: -- time_str '2016-11-20 04:31:11' -- date_str 20161120 select concat(left(date_format(time_str, '%y-%m-%d %h:%i'

模拟多级表头的分组统计

分组|统计 原帖地址:http://community.csdn.net/Expert/topic/3434/3434688.xml?temp=3.246486E-03 --测试数据create table 单位表 (单位代码 varchar(10),单位名称 varchar(50))insert 单位表 values('01'      ,'中国单位')             --1级insert 单位表 values('0101'    ,'山东单位')             --2级i

实现按部门月卡余额总额分组统计的SQL查询代码

分组|统计 陈优章的专栏 (原创,到现在为至最为复杂的SQL查询代码)实现按部门月卡余额总额分组统计的SQL查询代码(在Ms SQL Server中调试通过) SELECT dp.dpname1 AS 部门, cust_dp_SumOddfre.sum_oddfare AS 当月卡总余额FROM (SELECT T_Department.DpCode1, SUM(custid_SumOddfare_group.sum_oddfare)               AS sum_oddfare  

Access中分组统计的实例

access|分组|统计 Access中分组统计的实例 整理自:http://expert.csdn.net/Expert/topic/2727/2727523.xml?temp=.1140711 online 表下有字段: 描述:用户名 版本 是否注册 字段:usr_name ver isreg 现表中有以下记录: aaa cn true bbb cn false ccc en true ddd fr true 结果要求:查询每个版本的注册用户和未注册用户的数目,得出如下结构: 版本 注册数量

SQL的排序,分组,统计常用语句

  SQL的排序,分组,统计常用语句: 1.使用排序使数据有序 通常,你的所有数据真正需要的仅仅是按某种顺序排列.SQL的ORDER BY语句可以以字母或数字顺序组织数据.因此,相似的值按组排序在一起.然而,这个分组时排序的结果,并不是真的分组.ORDER BY显示每条记录而分组可能代表很多记录. 2.进行分组除去重复值 排序和分组之间的最大区别是:排序的数据显示所有记录(在限定标准范围之内),而分组数据不是显示所有记录.GROUP BY语句对于同样的值只显示一条记录.例如,下面的语句中的GRO

《卸甲笔记》-分组统计查询对比之二

13在分组查询的SELECT子句中出现其他字段(ename) Oracle SQL> select deptno,ename,COUNT(empno) 2 from emp 3 GROUP BY deptno; select deptno,ename,COUNT(empno) * ERROR at line 1: ORA-00979: not a GROUP BY expression PPAS scott=# select deptno,ename,COUNT(empno) scott-# f