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(0true);  
  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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值