Solr --- 聚合统计stats

来源:互联网 发布:php中app接口代码 编辑:程序博客网 时间:2024/05/29 03:05

简介

stats查询用于对文档中的数字型、字符型和日期型字段进行简单的统计。
 stats
设置为true,启用stat统计功能
 stats.field
指定产生stat统计的字段,可以提供多个字段。
 stats.facet
在给定的facet字段中返回子结果
 支持的统计信息
min 最小值
max 最大值
sum 所有值之和
count 值的个数
missing 空值个数
mean 平均值

查询语法

输入:

q=apple&stats=true&stats.field=price&stats.field=popularity

输出统计信息:

<lst name="stats"> <lst name="stats_fields">   <lst name="price">      <double name="min">0.0</double>      <double name="max">2199.0</double>      <long name="count">16</long>      <long name="missing">16</long>      <double name="sum">5251.270030975342</double>      <double name="sumOfSquares">6038619.175900028</double>     <double name="mean">328.20437693595886</double>     <double name="stddev">536.3536996709846</double>     <lst name="facets"/>   </lst>   <lst name="popularity">     <double name="min">0.0</double>     <double name="max">10.0</double>     <long name="count">15</long>     <long name="missing">17</long>     <double name="sum">85.0</double>     <double name="sumOfSquares">603.0</double>     <double name="mean">5.666666666666667</double>     <double name="stddev">2.943920288775949</double>     <lst name="facets"/>   </lst>  </lst></lst>

源码分析

1)stats组件/** * Stats component calculates simple statistics on numeric field values * @since solr 1.4 */public class StatsComponent extends SearchComponent {  public static final String COMPONENT_NAME = "stats";  @Override  '''(a)准备阶段'''  public void prepare(ResponseBuilder rb) throws IOException {    '''根据参数stats=true设置功能开关'''    if (rb.req.getParams().getBool(StatsParams.STATS,false)) {      rb.setNeedDocSet( true );      rb.doStats = true;      rb._statsInfo = new StatsInfo(rb);    }  }  @Override  '''(b)处理阶段'''  public void process(ResponseBuilder rb) throws IOException {    '''如果不需要统计,则返回'''    if (!rb.doStats) return;    '''保存统计结果的map'''    Map<String, StatsValues> statsValues = new LinkedHashMap<>();    '''循环处理“stats.field=price&stats.field=popularity”中每一个field'''    for (StatsField statsField : rb._statsInfo.getStatsFields()) {      '''一般情况,返回主查询语句q=apple的结果文档集'''      DocSet docs = statsField.computeBaseDocSet();      '''getOutputKey()返回“price/popularity”作为key,computeLocalStatsValues()返回StatsValues的子类,比如NumericStatsValues/DateStatsValues/StringStatsValues/EnumStatsValues等 '''      statsValues.put(statsField.getOutputKey(), statsField.computeLocalStatsValues(docs));    }    '''convertToResponse函数返回的结果即是2~25行的内容,计算统计值'''    rb.rsp.add( "stats", convertToResponse(statsValues) );  }}  public static NamedList<NamedList<NamedList<?>>> convertToResponse    (Map<String,StatsValues> statsValues) {    NamedList<NamedList<NamedList<?>>> stats = new SimpleOrderedMap<>();    NamedList<NamedList<?>> stats_fields = new SimpleOrderedMap<>();    stats.add("stats_fields", stats_fields);    '''遍历每一个StatsValues,调用getStatsValues计算统计值'''    for (Map.Entry<String,StatsValues> entry : statsValues.entrySet()) {      String key = entry.getKey();      NamedList stv = entry.getValue().getStatsValues();      stats_fields.add(key, stv);    }    return stats;  }}'''(2)AbstractStatsValues类负责各统计值的计算'''abstract class AbstractStatsValues<T> implements StatsValues {  '''返回key,value对,比如: min 0 max 2199.0 ...'''  '''此处的min/max/count...等是所有StatsValues子类公共输出'''  public NamedList<?> getStatsValues() {    NamedList<Object> res = new SimpleOrderedMap<>();    if (statsField.includeInResponse(Stat.min)) {      res.add("min", min);    }    if (statsField.includeInResponse(Stat.max)) {      res.add("max", max);    }    if (statsField.includeInResponse(Stat.count)) {      res.add("count", count);    }    if (statsField.includeInResponse(Stat.missing)) {      res.add("missing", missing);    }    if (statsField.includeInResponse(Stat.distinctValues)) {      res.add("distinctValues", distinctValues);    }    if (statsField.includeInResponse(Stat.countDistinct)) {      res.add("countDistinct", countDistinct);    }    if (statsField.includeInResponse(Stat.cardinality)) {      if (statsField.getIsShard()) {        res.add("cardinality", hll.toBytes());      } else {        res.add("cardinality", hll.cardinality());      }    }    '''此函数由各子类覆盖,定义各自特殊的输出值'''    addTypeSpecificStats(res);    '''facet输出'''    if (!facets.isEmpty()) {      // add the facet stats      NamedList<NamedList<?>> nl = new SimpleOrderedMap<>();      for (Map.Entry<String,Map<String,StatsValues>> entry : facets.entrySet()) {        NamedList<NamedList<?>> nl2 = new SimpleOrderedMap<>();        nl.add(entry.getKey(), nl2);        for (Map.Entry<String,StatsValues> e2 : entry.getValue().entrySet()) {          nl2.add(e2.getKey(), e2.getValue().getStatsValues());        }      }      res.add(FACETS, nl);    }    return res;  }}'''(3)StatsValues子类数字型NumericStatsValues类'''class NumericStatsValues extends AbstractStatsValues<Number> {  '''输出数字型特殊的特有的统计值sum, sumOfSquares, mean, stddev, and percentiles'''  @Override  protected void addTypeSpecificStats(NamedList<Object> res) {    if (statsField.includeInResponse(Stat.sum)) {      res.add("sum", sum);    }    if (statsField.includeInResponse(Stat.sumOfSquares)) {      res.add("sumOfSquares", sumOfSquares);    }    if (statsField.includeInResponse(Stat.mean)) {      res.add("mean", sum / count);    }    if (statsField.includeInResponse(Stat.stddev)) {      res.add("stddev", getStandardDeviation());    }    if (statsField.includeInResponse(Stat.percentiles)) {      if (statsField.getIsShard()) {        ByteBuffer buf = ByteBuffer.allocate(tdigest.byteSize()); // upper bound        tdigest.asSmallBytes(buf);        res.add("percentiles", Arrays.copyOf(buf.array(), buf.position()) );      } else {        NamedList<Object> percentileNameList = new NamedList<Object>();        for (Double percentile : statsField.getPercentilesList()) {          // Empty document set case          if (tdigest.size() == 0) {            percentileNameList.add(percentile.toString(), null);          } else {            Double cutoff = tdigest.quantile(percentile / 100);            percentileNameList.add(percentile.toString(), cutoff);          }        }        res.add("percentiles", percentileNameList);      }    }  }}

0 0
原创粉丝点击