聚合统计 #
一、Facet(分面) #
1.1 Facet概述 #
Facet用于对搜索结果进行分组统计,常用于:
- 分类导航
- 品牌筛选
- 价格区间
- 属性筛选
1.2 字段Facet #
bash
# 基本Facet
curl "http://localhost:8983/solr/mycore/select" \
-d "q=*:*" \
-d "facet=true" \
-d "facet.field=category"
响应示例
json
{
"facet_counts": {
"facet_fields": {
"category": [
"tech", 50,
"book", 30,
"news", 20
]
}
}
}
1.3 Facet参数 #
| 参数 | 说明 |
|---|---|
| facet | 是否开启Facet |
| facet.field | Facet字段 |
| facet.limit | 返回数量 |
| facet.sort | 排序方式 |
| facet.mincount | 最小数量 |
| facet.missing | 是否包含空值 |
| facet.prefix | 前缀过滤 |
| facet.contains | 包含过滤 |
1.4 多字段Facet #
bash
# 多字段Facet
curl "http://localhost:8983/solr/mycore/select" \
-d "q=*:*" \
-d "facet=true" \
-d "facet.field=category" \
-d "facet.field=brand" \
-d "facet.field=author"
1.5 Facet排序 #
bash
# 按数量排序(默认)
curl "http://localhost:8983/solr/mycore/select" \
-d "q=*:*" \
-d "facet=true" \
-d "facet.field=category" \
-d "facet.sort=count"
# 按字母排序
curl "http://localhost:8983/solr/mycore/select" \
-d "q=*:*" \
-d "facet=true" \
-d "facet.field=category" \
-d "facet.sort=index"
1.6 Facet限制 #
bash
# 限制返回数量
curl "http://localhost:8983/solr/mycore/select" \
-d "q=*:*" \
-d "facet=true" \
-d "facet.field=category" \
-d "facet.limit=10"
# 设置最小数量
curl "http://localhost:8983/solr/mycore/select" \
-d "q=*:*" \
-d "facet=true" \
-d "facet.field=category" \
-d "facet.mincount=5"
二、Range Facet #
2.1 数值范围 #
bash
# 价格范围Facet
curl "http://localhost:8983/solr/mycore/select" \
-d "q=*:*" \
-d "facet=true" \
-d "facet.range=price" \
-d "facet.range.start=0" \
-d "facet.range.end=1000" \
-d "facet.range.gap=100"
响应示例
json
{
"facet_counts": {
"facet_ranges": {
"price": {
"counts": [
"0.0", 10,
"100.0", 25,
"200.0", 30,
"300.0", 20
]
}
}
}
}
2.2 日期范围 #
bash
# 日期范围Facet
curl "http://localhost:8983/solr/mycore/select" \
-d "q=*:*" \
-d "facet=true" \
-d "facet.range=publish_date" \
-d "facet.range.start=NOW-1YEAR" \
-d "facet.range.end=NOW" \
-d "facet.range.gap=%2B1MONTH"
2.3 Range参数 #
| 参数 | 说明 |
|---|---|
| facet.range | 范围字段 |
| facet.range.start | 起始值 |
| facet.range.end | 结束值 |
| facet.range.gap | 间隔 |
| facet.range.hardend | 是否硬结束 |
| facet.range.other | 其他统计 |
三、Query Facet #
3.1 查询Facet #
bash
# 自定义查询Facet
curl "http://localhost:8983/solr/mycore/select" \
-d "q=*:*" \
-d "facet=true" \
-d "facet.query=price:[0 TO 100]" \
-d "facet.query=price:[100 TO 500]" \
-d "facet.query=price:[500 TO *]"
3.2 响应示例 #
json
{
"facet_counts": {
"facet_queries": {
"price:[0 TO 100]": 50,
"price:[100 TO 500]": 30,
"price:[500 TO *]": 20
}
}
}
四、Pivot Facet #
4.1 基本Pivot #
bash
# 多维度Facet
curl "http://localhost:8983/solr/mycore/select" \
-d "q=*:*" \
-d "facet=true" \
-d "facet.pivot=category,brand"
4.2 响应示例 #
json
{
"facet_counts": {
"facet_pivot": {
"category,brand": [
{
"field": "category",
"value": "tech",
"count": 50,
"pivot": [
{
"field": "brand",
"value": "Apple",
"count": 20
},
{
"field": "brand",
"value": "Samsung",
"count": 15
}
]
}
]
}
}
}
4.3 多层Pivot #
bash
# 三层Pivot
curl "http://localhost:8983/solr/mycore/select" \
-d "q=*:*" \
-d "facet=true" \
-d "facet.pivot=category,brand,price"
五、Stats(统计) #
5.1 基本统计 #
bash
# 统计字段
curl "http://localhost:8983/solr/mycore/select" \
-d "q=*:*" \
-d "stats=true" \
-d "stats.field=price"
5.2 响应示例 #
json
{
"stats": {
"stats_fields": {
"price": {
"min": 10.0,
"max": 999.0,
"count": 100,
"missing": 5,
"sum": 25000.0,
"sumOfSquares": 1000000.0,
"mean": 250.0,
"stddev": 150.0
}
}
}
}
5.3 统计指标 #
| 指标 | 说明 |
|---|---|
| min | 最小值 |
| max | 最大值 |
| count | 数量 |
| missing | 空值数量 |
| sum | 总和 |
| sumOfSquares | 平方和 |
| mean | 平均值 |
| stddev | 标准差 |
| median | 中位数 |
5.4 分组统计 #
bash
# 按分类统计
curl "http://localhost:8983/solr/mycore/select" \
-d "q=*:*" \
-d "stats=true" \
-d "stats.field=price" \
-d "stats.facet=category"
六、Grouping(分组) #
6.1 基本分组 #
bash
# 按字段分组
curl "http://localhost:8983/solr/mycore/select" \
-d "q=*:*" \
-d "group=true" \
-d "group.field=category" \
-d "group.limit=5"
6.2 响应示例 #
json
{
"grouped": {
"category": {
"matches": 100,
"groups": [
{
"groupValue": "tech",
"doclist": {
"numFound": 50,
"docs": [...]
}
}
]
}
}
}
6.3 分组参数 #
| 参数 | 说明 |
|---|---|
| group | 是否分组 |
| group.field | 分组字段 |
| group.limit | 每组数量 |
| group.sort | 组内排序 |
| group.ngroups | 返回组数 |
| group.truncate | 是否截断 |
6.4 查询分组 #
bash
# 按查询分组
curl "http://localhost:8983/solr/mycore/select" \
-d "q=*:*" \
-d "group=true" \
-d "group.query=price:[0 TO 100]" \
-d "group.query=price:[100 TO *]"
七、JSON Facet API #
7.1 基本语法 #
bash
# JSON Facet
curl -X POST "http://localhost:8983/solr/mycore/select" \
-H "Content-Type: application/json" \
-d '{
"query": "*:*",
"facet": {
"categories": {
"type": "terms",
"field": "category"
}
}
}'
7.2 Terms Facet #
bash
curl -X POST "http://localhost:8983/solr/mycore/select" \
-H "Content-Type: application/json" \
-d '{
"query": "*:*",
"facet": {
"categories": {
"type": "terms",
"field": "category",
"limit": 10,
"sort": {"count": "desc"}
}
}
}'
7.3 Range Facet #
bash
curl -X POST "http://localhost:8983/solr/mycore/select" \
-H "Content-Type: application/json" \
-d '{
"query": "*:*",
"facet": {
"price_ranges": {
"type": "range",
"field": "price",
"start": 0,
"end": 1000,
"gap": 100
}
}
}'
7.4 嵌套Facet #
bash
curl -X POST "http://localhost:8983/solr/mycore/select" \
-H "Content-Type: application/json" \
-d '{
"query": "*:*",
"facet": {
"categories": {
"type": "terms",
"field": "category",
"facet": {
"brands": {
"type": "terms",
"field": "brand"
},
"avg_price": "avg(price)"
}
}
}
}'
7.5 聚合函数 #
| 函数 | 说明 |
|---|---|
| sum(field) | 求和 |
| avg(field) | 平均值 |
| min(field) | 最小值 |
| max(field) | 最大值 |
| count() | 计数 |
| unique(field) | 唯一值数量 |
八、实战示例 #
8.1 电商商品统计 #
bash
curl "http://localhost:8983/solr/products/select" \
-d "q=手机" \
-d "facet=true" \
-d "facet.field=brand" \
-d "facet.field=category" \
-d "facet.range=price" \
-d "facet.range.start=0" \
-d "facet.range.end=10000" \
-d "facet.range.gap=1000" \
-d "stats=true" \
-d "stats.field=price" \
-d "stats.field=sales"
8.2 文章分类统计 #
bash
curl "http://localhost:8983/solr/articles/select" \
-d "q=*:*" \
-d "facet=true" \
-d "facet.pivot=category,author" \
-d "stats=true" \
-d "stats.field=views" \
-d "stats.facet=category"
8.3 日志分析统计 #
bash
curl "http://localhost:8983/solr/logs/select" \
-d "q=*:*" \
-d "facet=true" \
-d "facet.field=level" \
-d "facet.field=host" \
-d "facet.range=timestamp" \
-d "facet.range.start=NOW-1DAY" \
-d "facet.range.end=NOW" \
-d "facet.range.gap=%2B1HOUR"
8.4 使用JSON Facet #
bash
curl -X POST "http://localhost:8983/solr/products/select" \
-H "Content-Type: application/json" \
-d '{
"query": "category:手机",
"facet": {
"brands": {
"type": "terms",
"field": "brand",
"limit": 10,
"facet": {
"avg_price": "avg(price)",
"total_sales": "sum(sales)"
}
},
"price_stats": {
"type": "range",
"field": "price",
"start": 0,
"end": 10000,
"gap": 1000
}
}
}'
九、性能优化 #
9.1 使用DocValues #
xml
<field name="category" type="string" indexed="true" stored="true" docValues="true"/>
9.2 限制Facet数量 #
bash
# 限制返回数量
curl "http://localhost:8983/solr/mycore/select" \
-d "q=*:*" \
-d "facet=true" \
-d "facet.field=category" \
-d "facet.limit=10"
9.3 使用缓存 #
xml
<requestHandler name="/select" class="solr.SearchHandler">
<lst name="defaults">
<bool name="facet">true</bool>
<int name="facet.limit">10</int>
</lst>
</requestHandler>
十、总结 #
聚合统计对比:
| 功能 | 说明 | 适用场景 |
|---|---|---|
| Facet | 分面统计 | 分类导航 |
| Range Facet | 范围统计 | 价格区间 |
| Pivot Facet | 多维统计 | 组合筛选 |
| Stats | 数值统计 | 统计分析 |
| Grouping | 分组查询 | 结果去重 |
| JSON Facet | 灵活聚合 | 复杂统计 |
最佳实践:
- 使用DocValues优化性能
- 合理限制返回数量
- 使用JSON Facet进行复杂统计
- 缓存常用Facet结果
下一步,让我们学习高亮与建议!
最后更新:2026-03-27