zoukankan      html  css  js  c++  java
  • Lucene8学习:分组统计

    1.1. 分组统计

    既然是查询,就有可能会用到分组统计。下面介绍一下Lucene的分组统计:

    1.1.1. 创建索引

    要分组统计,创建索引的时候就要添加一个SortedDocValuesField

      1 /**
      2 
      3      * 添加索引
      4 
      5      */
      6 
      7     @Test
      8 
      9     public void addIndex() {
     10 
     11 try {
     12 
     13 // 获取lucene的写入方法
     14 
     15 writer = LuceneUtils.getIndexWriter();
     16 
     17  
     18 
     19 Document doc = new Document();
     20 
     21  
     22 
     23 // 书主键
     24 
     25 doc = new Document();
     26 
     27     doc.add(new StringField("bookid", "1345678", Field.Store.YES));
     28 
     29     // 书名
     30 
     31     doc.add(new StringField("bookname", "西游记", Field.Store.YES));  
     32 
     33     // 书的类型
     34 
     35     doc.add(new StringField("booktype", "小说", Field.Store.YES));  
     36 
     37     // 需要使用特定的field存储分组,需要排序及分组的话,要加上下面语句,注意默认SortedDocValuesField也是不存储的
     38 
     39     doc.add(new SortedDocValuesField("booktype", new BytesRef("小说")));
     40 
     41     // 书的价格
     42 
     43     doc.add(new NumericDocValuesField("bookprice", 123));  
     44 
     45     // 书的日期年份
     46 
     47     Field intPoint = new NumericDocValuesField("bookdate", 1066);
     48 
     49     doc.add(intPoint);
     50 
     51     intPoint = new StoredField("bookdate", 1066);
     52 
     53     doc.add(intPoint);
     54 
     55     // 书的内容
     56 
     57     doc.add(new TextField("bookcontent", "《西游记》又称央视86版《西游记》,改编自明123456789012345678 12333代小说家吴承恩同名文学古典名著。是由中央电视台、中国电视剧制作中心出品的一部25集古装神话剧。由杨洁执导,戴英禄,杨洁,邹忆青共同编剧,六小龄童、徐少华、迟重瑞、汪粤、马德华、闫怀礼等主演,李世宏、李扬、张云明、里坡等担任主要配音。 [1] 
    " +
     58 
     59      "该剧讲述的是孙悟空、猪八戒、沙僧辅保大唐高僧玄奘去西天取经,师徒四人一路抢滩涉险,降妖伏怪,历经八十一难,取回真经,终修正果的故事。
    " +
     60 
     61      "《西游记》于1982年7月3日开机,同年10月1日首播试集《除妖乌鸡国》。1986年春节在央视首播前11集,1988年25集播出。
    " +
     62 
     63      "1986年春节一经播出,轰动全国,老少皆宜,获得了极高评价,造就了89.4%的收视率神话,至今仍是寒暑假被重播最多的电视剧,重播次数超过3000次,依然百看不厌,成为一部公认的无法超越的经典。", Field.Store.YES));
     64 
     65     // 添加文档
     66 
     67             writer.addDocument(doc);
     68 
     69             
     70 
     71             // 书主键
     72 
     73 doc = new Document();
     74 
     75     doc.add(new StringField("bookid", "1533278", Field.Store.YES));
     76 
     77     // 书名
     78 
     79     doc.add(new StringField("bookname", "自然", Field.Store.YES));  
     80 
     81     // 书的类型
     82 
     83     doc.add(new StringField("booktype", "杂志", Field.Store.YES));  
     84 
     85     // 需要使用特定的field存储分组,需要排序及分组的话,要加上下面语句,注意默认SortedDocValuesField也是不存储的
     86 
     87     doc.add(new SortedDocValuesField("booktype", new BytesRef("杂志")));
     88 
     89     // 书的价格
     90 
     91     doc.add(new NumericDocValuesField("bookprice", 123));  
     92 
     93     // 书的日期年份
     94 
     95     Field intPoint2 = new NumericDocValuesField("bookdate", 1066);
     96 
     97     doc.add(intPoint);
     98 
     99     intPoint = new StoredField("bookdate", 1066);
    100 
    101     doc.add(intPoint);
    102 
    103     // 书的内容
    104 
    105     doc.add(new TextField("bookcontent", "宣扬科学,发表论文!", Field.Store.YES));
    106 
    107     // 添加文档
    108 
    109          writer.addDocument(doc);
    110 
    111             
    112 
    113     // 书主键
    114 
    115   doc = new Document();
    116 
    117       doc.add(new StringField("bookid", "12345678", Field.Store.YES));
    118 
    119       // 书名
    120 
    121       doc.add(new StringField("bookname", "水浒传", Field.Store.YES));   
    122 
    123       // 书的类型
    124 
    125       doc.add(new StringField("booktype", "小说", Field.Store.YES));  
    126 
    127       // 需要使用特定的field存储分组,需要排序及分组的话,要加上下面语句,注意默认SortedDocValuesField也是不存储的
    128 
    129     doc.add(new SortedDocValuesField("booktype", new BytesRef("小说")));
    130 
    131       // 书的价格
    132 
    133     doc.add(new NumericDocValuesField("bookprice", 123));  
    134 
    135     // 书的日期年份
    136 
    137     Field intPoint1 = new NumericDocValuesField("bookdate", 1666);
    138 
    139     doc.add(intPoint1);
    140 
    141     intPoint1 = new StoredField("bookdate", 1666);
    142 
    143     doc.add(intPoint1);
    144 
    145       // 书的内容
    146 
    147       doc.add(new TextField("bookcontent", "中国大陆,中央电视台无锡太湖影视城 43集
    " +
    148 
    149        "《水浒传》是由中央电视台与中国电视剧制作中心联合出品的43集电视连续剧,根据明代施耐123456789012345678庵的同名小说改编。 [1]  由张绍林执导,杨争光 、冉平改编,李雪健、周野芒、臧金生、丁海峰、赵小锐领衔主演。
    " +
    150 
    151        "该剧讲述的是宋朝徽宗时皇帝昏庸、奸臣当道、官府腐败、贪官污吏陷害忠良,弄得民不聊生,许多正直善良的人被官府逼得无路可走,被迫奋起反抗,最终108条好汉聚义梁山泊,但随后宋江对朝廷的投降使得一场轰轰烈烈的农民起义最后走向失败的故事。 [2] 
    " +
    152 
    153        "《水浒传》于1998年1月8日在中央电视台一套首播。 [3] 
    " +
    154 
    155        "2018年9月8日,9月15日,9月22日,央视四台《中国文艺》“向经典致敬”栏目播出《水浒传》20周年聚首专题节目", Field.Store.YES));
    156 
    157      
    158 
    159     // 添加文档
    160 
    161             writer.addDocument(doc);
    162 
    163     
    164 
    165             // 提交数据,第一次创建的时候需要提交,否则会报错
    166 
    167           long resultcode = writer.commit();
    168 
    169  
    170 
    171           if(resultcode > 0l) {
    172 
    173           System.out.println("成功建立索引");
    174 
    175           } else {
    176 
    177           System.out.println("建立索引失败");
    178 
    179           }
    180 
    181 } catch (IOException e) {
    182 
    183 e.printStackTrace();
    184 
    185 }  
    186 
    187     }

    1.1.2. 分组统计查询

      1 /**
      2  * 分组查询
      3  * @param param
      4  * @param rule
      5  * @return
      6  * @throws IOException
      7  */
      8     @Test
      9 public void GroupingStatistics() throws IOException{
     10 
     11 try {
     12 // 获取一个indexReader对象
     13 reader = LuceneUtils.getIndexReader();
     14 // 创建一个indexsearcher对象
     15 searcher = new IndexSearcher(reader);
     16 
     17 Query query = new MatchAllDocsQuery();
     18 
     19 GroupingUtil groupingUtil = new GroupingUtil();
     20 
     21 int curPage = 1;
     22 
     23 int pageSize = 10;
     24 
     25 // 控制每次返回几组
     26 int groupLimit = curPage*pageSize;
     27 // 控制每一页的组内文档数
     28 int groupDocsLimit = curPage*pageSize;
     29 // 控制组的偏移
     30 int groupOffset = 0;
     31 
     32  
     33 
     34 // 为了排除干扰因素,全部使用默认的排序方式,当然你还可以使用自己喜欢的排序方式
     35         // 初始值为命中的所有文档数,即最坏情况下,一个文档分成一组,那么文档数就是分组的总数
     36         int totalGroupCount = searcher.count(query);
     37         TopGroups<BytesRef> topGroups;
     38 
     39         System.out.println("#### 组的分页大小为:" + groupLimit);
     40 
     41         System.out.println("#### 组内分页大小为:" + groupDocsLimit);
     42 
     43 while (groupOffset < totalGroupCount) {//说明还有不同的分组
     44 
     45             // 控制组内偏移,每次开始遍历一个新的分组时候,需要将其归零
     46 
     47             int groupDocsOffset = 0;
     48 
     49             System.out.println("#### 开始组的分页");
     50 
     51             topGroups = groupingUtil.group(searcher, query, "booktype",
     52 
     53              groupDocsOffset, groupDocsLimit, groupOffset, groupLimit);
     54 
     55             // 具体搜了一次之后,就知道到底有多少组了,更新totalGroupCount为正确的值
     56 
     57             totalGroupCount = topGroups.totalGroupCount;
     58 
     59             GroupDocs<BytesRef>[] groups = topGroups.groups;
     60 
     61             // 开始对组进行遍历
     62 
     63             for (int i = 0; i < groups.length; i++) {
     64 
     65                 long totalHits = groupingUtil.iterGroupDocs(searcher, groups[i]);// 获得这个组内一共多少doc
     66 
     67                 // 获取数据
     68 
     69                     TotalHits totalH = groups[i].totalHits;
     70 
     71                     totalHits = totalH.value;
     72 
     73                     System.out.println("	#### 开始组内分页");
     74 
     75                     System.out.println("	分组名称:" + groups[i].groupValue.utf8ToString());
     76 
     77                     ScoreDoc[] scoreDocs = groups[i].scoreDocs;
     78 
     79                     
     80 
     81                     if(scoreDocs!=null && scoreDocs.length>0) {
     82 
     83                      for (int j=0; j<1; j++) {
     84 
     85              Document document = searcher.doc(scoreDocs[j].doc);
     86 
     87              // 打印content字段的值
     88 
     89              System.out.println("得分值: "+scoreDocs.length);
     90 
     91              System.out.println("bookid: "+document.get("bookid"));
     92 
     93              System.out.println("bookname: "+document.get("bookname"));
     94 
     95              System.out.println("booktype: "+document.get("booktype"));
     96 
     97              System.out.println("bookprice: "+document.get("bookprice"));
     98 
     99              System.out.println("bookcontent: "+document.get("bookcontent"));
    100 
    101              }
    102 
    103                     }
    104 
    105                 groupDocsOffset = 0;
    106 
    107             }
    108 
    109             groupOffset += groupLimit;
    110 
    111             System.out.println("#### 结束组的分页");
    112 
    113         }
    114 
    115 } catch (Exception e) {
    116 
    117 e.printStackTrace();
    118 
    119 } finally {
    120 
    121 // 关闭indexReader对象
    122 
    123 reader.close();
    124 
    125 }
    126 
    127 }

    结果如下:

    #### 组的分页大小为:10

    #### 组内分页大小为:10

    #### 开始组的分页

    2019-11-15 11:43:21,051 INFO  (GroupingUtil.java:30) - #### 开始组内分页

    2019-11-15 11:43:21,067 INFO  (GroupingUtil.java:31) - 分组名称:小说

    2019-11-15 11:43:21,082 INFO  (GroupingUtil.java:34) - 组内记录:Document<stored,indexed,tokenized,omitNorms,indexOptions=DOCS<bookid:1345678> stored,indexed,tokenized,omitNorms,indexOptions=DOCS<bookname:西游记> stored,indexed,tokenized,omitNorms,indexOptions=DOCS<booktype:小说> stored<bookdate:1066> stored,indexed,tokenized<bookcontent:《西游记》又称央视86版《西游记》,改编自明123456789012345678 12333代小说家吴承恩同名文学古典名著。是由中央电视台、中国电视剧制作中心出品的一部25集古装神话剧。由杨洁执导,戴英禄,杨洁,邹忆青共同编剧,六小龄童、徐少华、迟重瑞、汪粤、马德华、闫怀礼等主演,李世宏、李扬、张云明、里坡等担任主要配音。 [1]

    该剧讲述的是孙悟空、猪八戒、沙僧辅保大唐高僧玄奘去西天取经,师徒四人一路抢滩涉险,降妖伏怪,历经八十一难,取回真经,终修正果的故事。

    《西游记》于1982年7月3日开机,同年10月1日首播试集《除妖乌鸡国》。1986年春节在央视首播前11集,1988年25集播出。

    1986年春节一经播出,轰动全国,老少皆宜,获得了极高评价,造就了89.4%的收视率神话,至今仍是寒暑假被重播最多的电视剧,重播次数超过3000次,依然百看不厌,成为一部公认的无法超越的经典。>>

    2019-11-15 11:43:21,082 INFO  (GroupingUtil.java:34) - 组内记录:Document<stored,indexed,tokenized,omitNorms,indexOptions=DOCS<bookid:12345678> stored,indexed,tokenized,omitNorms,indexOptions=DOCS<bookname:水浒传> stored,indexed,tokenized,omitNorms,indexOptions=DOCS<booktype:小说> stored<bookdate:1666> stored,indexed,tokenized<bookcontent:中国大陆,中央电视台无锡太湖影视城 43集

    《水浒传》是由中央电视台与中国电视剧制作中心联合出品的43集电视连续剧,根据明代施耐123456789012345678庵的同名小说改编。 [1]  由张绍林执导,杨争光 、冉平改编,李雪健、周野芒、臧金生、丁海峰、赵小锐领衔主演。

    该剧讲述的是宋朝徽宗时皇帝昏庸、奸臣当道、官府腐败、贪官污吏陷害忠良,弄得民不聊生,许多正直善良的人被官府逼得无路可走,被迫奋起反抗,最终108条好汉聚义梁山泊,但随后宋江对朝廷的投降使得一场轰轰烈烈的农民起义最后走向失败的故事。 [2]

    《水浒传》于1998年1月8日在中央电视台一套首播。 [3]

    2018年9月8日,9月15日,9月22日,央视四台《中国文艺》“向经典致敬”栏目播出《水浒传》20周年聚首专题节目>>

    2019-11-15 11:43:21,098 INFO  (GroupingUtil.java:36) - #### 结束组内分页

    #### 开始组内分页

    分组名称:小说

    得分值: 2

    bookid: 1345678

    bookname: 西游记

    booktype: 小说

    bookprice: null

    bookcontent: 《西游记》又称央视86版《西游记》,改编自明123456789012345678 12333代小说家吴承恩同名文学古典名著。是由中央电视台、中国电视剧制作中心出品的一部25集古装神话剧。由杨洁执导,戴英禄,杨洁,邹忆青共同编剧,六小龄童、徐少华、迟重瑞、汪粤、马德华、闫怀礼等主演,李世宏、李扬、张云明、里坡等担任主要配音。 [1]

    该剧讲述的是孙悟空、猪八戒、沙僧辅保大唐高僧玄奘去西天取经,师徒四人一路抢滩涉险,降妖伏怪,历经八十一难,取回真经,终修正果的故事。

    《西游记》于1982年7月3日开机,同年10月1日首播试集《除妖乌鸡国》。1986年春节在央视首播前11集,1988年25集播出。

    1986年春节一经播出,轰动全国,老少皆宜,获得了极高评价,造就了89.4%的收视率神话,至今仍是寒暑假被重播最多的电视剧,重播次数超过3000次,依然百看不厌,成为一部公认的无法超越的经典。

    2019-11-15 11:43:21,098 INFO  (GroupingUtil.java:30) - #### 开始组内分页

    2019-11-15 11:43:21,098 INFO  (GroupingUtil.java:31) - 分组名称:杂志

    2019-11-15 11:43:21,098 INFO  (GroupingUtil.java:34) - 组内记录:Document<stored,indexed,tokenized,omitNorms,indexOptions=DOCS<bookid:1533278> stored,indexed,tokenized,omitNorms,indexOptions=DOCS<bookname:自然> stored,indexed,tokenized,omitNorms,indexOptions=DOCS<booktype:杂志> stored<bookdate:1066> stored,indexed,tokenized<bookcontent:宣扬科学,发表论文!>>

    2019-11-15 11:43:21,098 INFO  (GroupingUtil.java:36) - #### 结束组内分页

    #### 开始组内分页

    分组名称:杂志

    得分值: 1

    bookid: 1533278

    bookname: 自然

    booktype: 杂志

    bookprice: null

    bookcontent: 宣扬科学,发表论文!

    #### 结束组的分页

    2019-11-15 11:43:21,145 INFO  (LuceneUtils.java:58) - --------Lucene释放关闭资源中....

    2019-11-15 11:43:21,145 INFO  (LuceneUtils.java:76) - --------Lucene释放关闭资源成功....

    1.1.3. GroupingUtil

      1 import java.io.IOException;
      2 import org.apache.lucene.search.IndexSearcher;
      3 import org.apache.lucene.search.Query;
      4 import org.apache.lucene.search.ScoreDoc;
      5 import org.apache.lucene.search.Sort;
      6 import org.apache.lucene.search.TotalHits;
      7 import org.apache.lucene.search.grouping.GroupDocs;
      8 import org.apache.lucene.search.grouping.GroupingSearch;
      9 import org.apache.lucene.search.grouping.TopGroups;
     10 import org.apache.lucene.util.BytesRef;
     11 import org.slf4j.Logger;
     12 import org.slf4j.LoggerFactory;
     13 /**
     14  * Lucene8
     15  * 分组统计查询
     16  * @author limingcheng
     17  *
     18  */
     19 public class GroupingUtil {
     20 
     21 private static final Logger logger = LoggerFactory.getLogger(GroupingUtil.class);
     22 
     23     public long iterGroupDocs(IndexSearcher indexSearcher, GroupDocs<BytesRef> groupDocs) throws IOException {
     24 
     25         TotalHits totalHits = groupDocs.totalHits;
     26 
     27         long rsvalue = totalHits.value;
     28 
     29         logger.info("	#### 开始组内分页");
     30 
     31         logger.info("	分组名称:" + groupDocs.groupValue.utf8ToString());
     32 
     33         ScoreDoc[] scoreDocs = groupDocs.scoreDocs;
     34 
     35         for (ScoreDoc scoreDoc : scoreDocs) {
     36 
     37          logger.info("		组内记录:" + indexSearcher.doc(scoreDoc.doc));
     38 
     39         }
     40 
     41         logger.info("	#### 结束组内分页");
     42 
     43         return rsvalue;
     44 
     45     }
     46 
     47  
     48 
     49     public TopGroups<BytesRef> group(IndexSearcher indexSearcher, Query query, String groupField,
     50 
     51                                      int groupDocsOffset, int groupDocsLimit, int groupOffset, int groupLimit) throws Exception {
     52 
     53         return group(indexSearcher, query, Sort.RELEVANCE, Sort.RELEVANCE, groupField, groupDocsOffset, groupDocsLimit, groupOffset, groupLimit);
     54 
     55     }
     56 
     57 
     58     /**
     59 
     60      * 分组统计查询
     61 
     62      * @param indexSearcher
     63 
     64      * @param query
     65 
     66      * @param groupSort
     67 
     68      * @param withinGroupSort
     69 
     70      * @param groupField
     71 
     72      * @param groupDocsOffset
     73 
     74      * @param groupDocsLimit
     75 
     76      * @param groupOffset
     77 
     78      * @param groupLimit
     79 
     80      * @return
     81 
     82      * @throws Exception
     83 
     84      */
     85 
     86     public TopGroups<BytesRef> group(IndexSearcher indexSearcher, Query query, Sort groupSort, Sort withinGroupSort,
     87 
     88      String groupField, int groupDocsOffset, int groupDocsLimit, int groupOffset, int groupLimit)
     89 
     90      throws Exception {
     91 
     92         //实例化GroupingSearch实例,传入分组域
     93 
     94         GroupingSearch groupingSearch = new GroupingSearch(groupField);
     95 
     96         //设置组间排序方式
     97 
     98         groupingSearch.setGroupSort(groupSort);
     99 
    100         //设置组内排序方式
    101 
    102         groupingSearch.setSortWithinGroup(withinGroupSort);
    103 
    104         //是否要填充每个返回的group和groups docs的排序field
    105 
    106 //        groupingSearch.setFillSortFields(true);
    107 
    108         //设置用来缓存第二阶段搜索的最大内存,单位MB,第二个参数表示是否缓存评分
    109 
    110         groupingSearch.setCachingInMB(64.0, true);
    111 
    112         //是否计算符合查询条件的所有组
    113 
    114         groupingSearch.setAllGroups(true);
    115 
    116         groupingSearch.setAllGroupHeads(true);
    117 
    118         //设置一个分组内的上限
    119 
    120         groupingSearch.setGroupDocsLimit(groupDocsLimit);
    121 
    122         //设置一个分组内的偏移
    123 
    124         groupingSearch.setGroupDocsOffset(groupDocsOffset);
    125 
    126         TopGroups<BytesRef> result = groupingSearch.search(indexSearcher, query, groupOffset, groupLimit);
    127 
    128         return result;
    129 
    130     }
    131 
    132 }
  • 相关阅读:
    【总结】搜索
    【luogu】p2296 寻找道路
    【luogu】p2058 海港
    【总结】二叉搜索树
    【总结】线段树
    【总结】矩阵快速幂
    【笔记】很基础的数论知识
    【总结】扩展欧几里得算法
    【总结】二分查找
    【高精度乘法】例1.4 课本185页
  • 原文地址:https://www.cnblogs.com/bestlmc/p/11865756.html
Copyright © 2011-2022 走看看