以下是对 Apache Solr 的简介及其常用语法的快速入门指南:
一、Solr 是什么?
• 核心定位:Apache Solr 是一个基于 Lucene 的高性能、开源的搜索平台,支持全文检索、分词、高亮、聚合统计等功能。
• 核心功能:
• 全文搜索:快速检索海量文本数据。
• 数据聚合(Facet):统计字段分布、范围、词频等。
• 分布式架构:支持水平扩展,处理 PB 级数据。
• 实时索引:支持近实时(NRT)数据更新。
• 适用场景:电商搜索、日志分析、大数据检索、推荐系统等。
二、快速安装与启动
1. 下载与启动
# 下载 Solr(以 9.x 为例)
wget https://dlcdn.apache.org/solr/solr/9.5.0/solr-9.5.0.tgz
tar -xzf solr-9.5.0.tgz
cd solr-9.5.0
# 启动 Solr(单机模式)
bin/solr start
2. 创建核心(Core)
bin/solr create -c my_core
三、常用语法示例
1. 基础查询(q)
• 搜索所有文档:
q=*:*
• 指定字段搜索:
q=title:"智能手机"
• 多条件组合(布尔逻辑):
q=title:apple AND (category:phone OR price:[1000 TO 2000])
2. 过滤查询(fq)
• 过滤特定分类:
fq=category:electronics
• 范围过滤(价格 100-500):
fq=price:[100 TO 500]
3. 排序(sort)
• 按价格升序,评分降序:
sort=price asc, score desc
4. 分页(start 和 rows)
• 获取第 2 页,每页 10 条:
start=10&rows=10
5. 返回字段限制(fl)
• 指定返回字段:
fl=id,title,price
• 包含评分和计算字段:
fl=title,price,score,sum(price,tax) as total
6. 高亮(hl)
• 高亮标题和内容中的关键词:
hl=true&hl.fl=title,content
7. 分组(group)
• 按分类分组,每组返回前 3 条:
group=true&group.field=category&group.limit=3
8. 分面统计(facet)
• 统计分类分布和价格区间:
facet=true
&facet.field=category
&facet.range=price
&facet.range.start=0
&facet.range.end=1000
&facet.range.gap=100
四、高级功能语法
1. 使用 eDisMax 解析器
defType=edismax
&qf=title^2 content^1 # 字段加权
&bq=in_stock:true^10 # 提升库存商品
&bf=log(sales) # 按销量动态加权
2. 模糊搜索与通配符
• 模糊匹配(允许 1 字符差异):
q=applle~1
• 通配符搜索:
q=title:app* # 匹配 "apple", "application" 等
3. 函数查询
• 按时间衰减排序:
sort=recip(ms(NOW,create_time),1,1000,1000) desc
五、最佳实践
优先使用 fq 过滤:提升性能(结果可缓存)。限制返回字段(fl):减少网络传输开销。避免全通配符 *:*:大数据集下性能差。合理配置分词器:根据业务需求定制字段的分词规则。
六、总结
Solr 是一个功能强大的搜索引擎,适用于复杂查询和大规模数据场景。掌握以上语法后,可快速实现以下操作:
• 基础搜索、过滤、排序
• 聚合统计(分面、分组)
• 动态评分与高亮
• 分布式扩展与优化
通过结合 eDisMax 解析器和函数查询,能实现更灵活的搜索排序策略!
一、常用内置函数
1. 数学函数
函数
说明
示例
应用场景
abs(x)
绝对值
abs(-5)
→ 5
计算误差范围
sqrt(x)
平方根
sqrt(16)
→ 4
数据标准化处理
log(x)
自然对数
log(10)
→ 2.302
平滑指数(如销量加权)
pow(x,y)
x 的 y 次幂
pow(2,3)
→ 8
非线性评分调整
sum(x,y,...)
求和
sum(1,2,3)
→ 6
多字段数值相加
product(x,y,...)
乘积
product(2,3)
→ 6
综合权重计算
div(x,y)
除法
div(10,2)
→ 5
计算单价、比率
场景示例:
商品评分加权:log(sales)*0.5 + rating*10价格区间标准化:div(price, 100) 将价格转换为百元单位。
2. 字符串函数
函数
说明
示例
应用场景
concat(str1,str2)
字符串拼接
concat("Hello","World")
→ "HelloWorld"
生成复合字段
split(str,sep)
按分隔符拆分字符串
split("A,B,C", ",")
→ ["A","B","C"]
多标签分类统计
substr(str,start,len)
截取子字符串
substr("Solr",1,2)
→ "ol"
提取部分编码字段
strdist(str1,str2,alg)
计算字符串相似度
strdist("apple","app", "jw")
→ 0.96
模糊匹配度评分
场景示例:
地址模糊匹配:strdist(address, "北京市海淀区", "jw")动态生成标题:concat(brand, "-", model)。
3. 日期函数
函数
说明
示例
应用场景
now()
当前时间
now()
→ "2024-07-30T12:00:00Z"
实时数据过滤
ms(date1, date2)
计算两个日期的毫秒差
ms(now(), publish_time)
→ 86400000
时间衰减排序
dateMath(expr)
日期运算
dateMath(now()-1DAY)
动态时间范围过滤
场景示例:
新闻时效性排序:recip(ms(now(), publish_time), 3.16e-11, 1, 1)过滤最近一周数据:fq=publish_date:[NOW-7DAYS TO NOW]。
4. 条件与逻辑函数
函数
说明
示例
应用场景
if(cond, trueVal, falseVal)
条件判断
if(price>100, "高价", "低价")
动态分类标记
exists(field)
判断字段是否存在
exists(description)
→ 1 或 0
过滤缺失关键字段的文档
and(x,y)
/ or(x,y)
逻辑与/或
and(in_stock, price<100)
组合布尔条件
场景示例:
促销商品标识:if(is_promotion, "促销中", "无促销")过滤无效商品:fq=exists(image_url)。
二、聚合函数(Faceting)
Solr 的聚合统计通过 Facet 实现,核心函数如下:
聚合类型
说明
示例
应用场景
count
统计文档数
facet.field=category
按分类统计商品数量
sum
求和
facet.query=sum(sales)
计算总销售额
avg
平均值
facet.query=avg(price)
计算平均价格
min
/ max
最小值/最大值
facet.query=min(price)
价格区间分析
unique
唯一值计数(基数统计)
facet.query=unique(user_id)
统计独立访问用户数
range
按范围分组统计
facet.range=price&facet.range.start=0&...
价格区间分布统计
场景示例:
电商数据分析:
bash
facet=true
&facet.field=category
&facet.query=sum(sales)
&facet.range=price
&facet.range.start=0
&facet.range.end=1000
&facet.range.gap=100
输出结果:
各分类商品数总销售额价格在 0-100、100-200 等区间的商品数量。
三、高级应用场景
1. 综合评分排序(电商搜索)
bash
q=手机&
defType=edismax&
qf=title^2 brand^1&
bf=product(log(sales), recip(price,1,1000,1000))&
fl=title,price,sales,score
效果:销量高且价格低的商品排名更靠前。
2. 时间衰减排序(新闻推荐)
bash
q=科技&
bf=recip(ms(NOW,publish_time), 3.16e-11, 1, 1)&
fl=title,publish_time,score
效果:新发布的新闻优先展示。
3. 动态价格分段统计(数据分析)
bash
facet.range=price&
facet.range.start=0&
facet.range.end=1000&
facet.range.gap=100&
facet=on
效果:统计不同价格区间的商品数量(0-100元、100-200元等)。
四、最佳实践
优先使用 fq 过滤数据:提升聚合性能。避免复杂函数嵌套:如 sqrt(log(div(x,y))) 可能影响性能。合理选择聚合粒度:范围查询(facet.range)的间隔(gap)不宜过小。结合缓存机制:对高频聚合查询启用结果缓存。
日期查询【最近七天】:
在 Solr 中,日期范围查询的正确语法应使用 **NOW 和日期数学表达式**,而不是 date_math 函数。以下是修复后的语法及详细说明:
正确语法
bash
create_time:[NOW-7DAYS TO NOW]
或(更严谨的格式,指定时间单位):
bash
create_time:[NOW-7DAYS/DAY TO NOW/DAY] # 精确到天的范围
语法说明
1. 核心规则
**NOW**:表示当前时间(UTC 时区)。**-7DAYS**:日期数学表达式,向前推 7 天。**[start TO end]**:闭区间范围(包含边界值)。**/DAY**:将时间截断到天级别(可选,用于对齐日期边界)。
2. 动态时间计算
表达式
含义
示例值(假设当前为 2024-07-30
)
NOW-7DAYS
7 天前的当前时刻
2024-07-23T12:00:00Z
NOW-7DAYS/DAY
7 天前的零点(UTC)
2024-07-23T00:00:00Z
NOW/DAY
当前日期的零点(UTC)
2024-07-30T00:00:00Z
3. URL 转义
在 HTTP 请求中需转义特殊字符(如 [, ], /):
bash
# 实际请求示例(注意转义方括号和斜杠)
q=create_time:%5BNOW-7DAYS%20TO%20NOW%5D
完整示例
场景:查询最近 7 天内创建的数据
bash
http://localhost:8983/solr/your-core/select?
q=*:*&
fq=create_time:[NOW-7DAYS TO NOW]&
fl=id,create_time
结果
json
{
"response": {
"docs": [
{ "id": "1", "create_time": "2024-07-25T08:30:00Z" },
{ "id": "2", "create_time": "2024-07-28T15:45:00Z" }
]
}
}
常见问题
1. 时区问题
Solr 默认使用 UTC 时区,若数据存储为本地时间(如 CST),需转换时区:
bash
create_time:[NOW-7DAYS+8HOURS TO NOW+8HOURS] # 假设数据为 UTC+8 时区
2. 字段类型
确保 create_time 字段类型为 Solr 日期类型(如 date 或 datePoint)。
3. 精确时间对齐
若需按天过滤(忽略时分秒),使用截断语法:
bash
create_time:[NOW-7DAYS/DAY TO NOW/DAY]
等价于:
bash
create_time:[2024-07-23T00:00:00Z TO 2024-07-30T00:00:00Z]
进阶用法
动态时间范围
结合参数化请求(如 $__time 占位符):
bash
create_time:[$__time-7DAYS TO $__time]
通过此语法,你可以精准筛选出指定时间范围内的文档,避免语法错误!
bq bf q^的区别
在 Solr 中,bq(Boost Query)、bf(Boost Function)和 q 中的 ^ 字段加权都能影响文档评分,但它们的机制和应用场景有本质区别。以下是详细对比和场景指南:
一、核心区别
功能
**q
字段加权 (title^2
)**
**bq
**
**bf
**
作用阶段
主查询的匹配评分计算阶段
主查询后,添加额外查询条件并加权
主查询后,通过函数动态调整评分
评分机制
直接影响字段的匹配得分(TF-IDF 等)
独立计算附加条件的得分,再叠加到总分
根据函数计算结果直接调整总分
适用场景
简单字段优先级调整
复杂逻辑的条件加权(如促销、库存)
动态数值计算(如时间衰减、销量加权)
语法灵活性
仅支持字段加权
支持完整 Lucene 查询语法
支持 Solr 函数表达式
二、使用场景对比
1. q 中的字段加权 (title^2)
场景:明确提升某个字段的匹配权重。示例:
bash
q=title:apple^2 content:apple
title 字段匹配 "apple" 的得分是 content 的 2 倍。
2. bq(Boost Query)
场景:基于额外条件(如库存状态、分类)提升评分。示例:
bash
q=title:apple&bq=in_stock:true^10
主查询匹配 "apple",库存为 true 的文档总分额外增加 10 倍。
3. bf(Boost Function)
场景:根据动态数值(如时间、销量)调整评分。示例:
bash
q=title:apple&bf=log(sales)^2
销量越高的文档,评分提升越多(按对数计算)。
三、为什么需要 bq 和 bf?
1. 解决 q 字段加权的局限性
无法处理复杂条件:
q 中的 ^ 仅能加权字段匹配得分,而 bq 可以附加任意查询条件(如 in_stock:true AND price<100)。无法动态计算评分:
bf 支持数学函数(如时间衰减 recip(ms(NOW,date))),直接操作评分值。
2. 提升灵活性和性能
独立评分叠加:
bq 和 bf 的评分独立于主查询,可复用缓存结果(如 fq 过滤后的文档集)。解耦业务逻辑:
将主查询(相关性匹配)与业务规则(如促销优先级)分离,便于维护。
四、为什么需要 eDisMax?
1. 扩展 DisMax 的局限性
DisMax 不足:
不支持通配符 (*)、模糊搜索 (~)、布尔逻辑 (AND/OR)。无法使用 bq 和 bf 等高级功能。
eDisMax 增强:
支持所有 DisMax 功能 + 通配符、模糊搜索、函数查询。允许更复杂的评分策略(bq/bf)。
2. 典型场景
电商搜索:
bash
defType=edismax
q=apple watch
qf=title^2 content^1
bq=is_promotion:true^100
bf=log(sales)^2
主查询匹配关键词,促销商品和高销量商品优先排序。
五、推荐使用策略
优先使用 qf + ^:
明确提升关键字段的匹配权重(如 title 比 content 更重要)。复杂条件用 bq:
需要组合多个字段或业务规则时(如 in_stock:true AND category:electronics)。动态计算用 bf:
依赖数值、时间等动态因素时(如新发布的文档优先)。始终选择 eDisMax:
除非明确需要 DisMax 的极简功能,否则优先使用 eDisMax 的扩展能力。
六、总结
**q 字段加权**:简单直接,适合基础相关性优化。**bq**:灵活添加业务规则,适合条件叠加。**bf**:动态数值计算,适合时间、销量等场景。eDisMax:功能全面,是复杂搜索场景的首选解析器。
分面分组的区别
一句话总结:
• 分面:统计字段分布(如分类数量统计)
• 分组:按字段将文档归类(如按作者显示所有文章)
1. 分面(Faceting)
作用:统计字段值的分布情况。
示例:统计商品分类的数量
q=*:*&
facet=true&
facet.field=category
返回结果:
"facet_counts": {
"category": {
"electronics": 120,
"books": 80,
"clothing": 200
}
}
2. 分组(Grouping)
作用:按字段将文档分组,每组显示指定数量的文档。
示例:按作者分组显示文章(每组最多3篇)
q=*:*&
group=true&
group.field=author&
group.limit=3
返回结果:
"groups": {
"author": {
"groups": [
{
"groupValue": "张三",
"doclist": [{文章1}, {文章2}, {文章3}]
},
{
"groupValue": "李四",
"doclist": [{文章A}, {文章B}]
}
]
}
}
eDisMax vs DisMax的区别
一句话总结:
• DisMax:基础版,支持简单字段加权,不支持通配符/模糊搜索。
• eDisMax:增强版,支持通配符/模糊搜索/布尔逻辑,推荐优先使用。
1. DisMax 示例
q=apple watch&
defType=dismax&
qf=title^2 content
结果:
• 搜索 title 或 content 中的 "apple watch"。
• 不支持 apple* 或 apple~ 等语法。
2. eDisMax 示例
q=(apple OR samsung) AND phone~2&
defType=edismax&
qf=title^3 brand
结果:
• 搜索 "apple" 或 "samsung",且包含 "phone"(允许2个字符差异)。
• 支持通配符(app*)、模糊搜索(phone~2)、布尔逻辑(AND/OR)。
三、对比总结
功能
分面(Faceting)
分组(Grouping)
DisMax
eDisMax
核心用途
统计字段分布
按字段归类文档
简单多字段搜索
高级搜索(通配符/模糊)
返回形式
统计数值(如数量)
按组返回文档列表
普通文档列表
普通文档列表
典型场景
商品分类数量统计
按作者显示所有文章
基础搜索框
复杂搜索(电商/日志)
是否改结构
不改结构,只加统计
改变结构,分组展示
-
-
一句话选型:
• 需要统计字段分布 → 分面
• 需要按字段归类文档 → 分组
• 需要通配符/模糊搜索 → eDisMax