1. 概述
本文将深入探讨 Apache Solr 搜索引擎的核心功能——全文搜索。Apache Solr 是一款开源框架,专为处理海量文档而设计。我们将通过 Java 库 SolrJ 的实际案例,解析其核心能力。
✅ 关键点:
- Solr 支持百万级文档处理
- 使用 SolrJ 库简化 Java 集成
- 聚焦实用开发场景
2. Maven 配置
由于 Solr 是开源项目,我们可以直接下载二进制包独立运行服务器。在应用中集成时,需添加 SolrJ 客户端依赖:
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
<version>6.4.2</version>
</dependency>
⚠️ 最新版本可在此处查看:Maven 中央仓库
3. 数据索引
要索引和搜索数据,需先创建一个 core(核心)。我们创建名为 item 的 core 来存储数据。索引前需确保数据已导入服务器,Solr 提供多种索引方式:
- 使用数据导入处理器直接从关系数据库导入
- 通过 Solr Cell 利用 Apache Tika 上传文件
- 使用索引处理器上传 XML/XSLT、JSON、CSV 数据
3.1. 索引 Solr 文档
通过创建 SolrInputDocument
进行索引:
SolrInputDocument doc = new SolrInputDocument();
doc.addField("id", id);
doc.addField("description", description);
doc.addField("category", category);
doc.addField("price", price);
solrClient.add(doc);
solrClient.commit();
⚠️ 注意:
id
字段必须唯一- 重复
id
会更新现有文档
3.2. 索引 Java Bean
使用 @Field
注解标注 Bean 字段:
public class Item {
@Field
private String id;
@Field
private String description;
@Field
private String category;
@Field
private float price;
}
索引操作非常直接:
solrClient.addBean(item);
solrClient.commit();
4. Solr 查询
搜索是 Solr 的核心能力。索引完成后,可执行关键词、短语、日期范围等查询,结果按相关性(得分)排序。
4.1. 基础查询
服务器提供 /select
或 /query
接口处理搜索请求。简单查询示例:
SolrQuery query = new SolrQuery();
query.setQuery("brand1");
query.setStart(0);
query.setRows(10);
QueryResponse response = solrClient.query(query);
List<Item> items = response.getBeans(Item.class);
✅ 关键特性:
- 默认返回 10 条记录(从 0 开始)
- 搜索不区分大小写
- 支持通配符(
*
和?
):query.setQuery("*rand?"); // 匹配如 "brand" 等词
- 支持布尔运算符(AND、OR、NOT):
query.setQuery("brand1 AND (Washing OR Refrigerator)");
- 指定字段搜索:
query.setQuery("description:Brand* AND category:*Washing*");
4.2. 短语查询
默认查询解析器会将短语拆分为 OR 关系。需用双引号强制完整匹配:
query.setQuery("\"Washing Machine\"");
⚠️ 邻近搜索(proximity search)示例:
query.setQuery("\"Washing equipment\"~2"); // 允许间隔两个单词
4.3. 范围查询
查询数值范围内的文档:
query.setQuery("price:[100 TO 300]"); // 包含边界
query.setQuery("price:{100 TO 300]"); // 排除下边界
4.4. 过滤查询
使用 addFilterQuery
限制结果集,不影响评分:
SolrQuery query = new SolrQuery();
query.setQuery("price:[100 TO 300]");
query.addFilterQuery("description:Brand1","category:Home Appliances");
✅ 优势:
- 过滤条件会被缓存
- 显著提升高频查询性能
5. 分面搜索
分面(Faceting)将搜索结果按分组聚合统计,支持字段、查询和范围分面。
5.1. 字段分面
获取分类的聚合统计:
query.addFacetField("category");
QueryResponse response = solrClient.query(query);
List<Count> facetResults = response.getFacetField("category").getValues();
5.2. 查询分面
统计子查询的匹配数:
query.addFacetQuery("Washing OR Refrigerator");
query.addFacetQuery("Brand2");
QueryResponse response = solrClient.query(query);
Map<String,Integer> facetQueryMap = response.getFacetQuery();
5.3. 范围分面
按数值区间统计(如价格分段):
query.addNumericRangeFacet("price", 100, 275, 25); // 起始100,结束275,步长25
QueryResponse response = solrClient.query(query);
List<RangeFacet> rangeFacets = response.getFacetRanges().get(0).getCounts();
Solr 还支持日期范围、区间分面和轴心分面(Pivot Faceting)
6. 高亮显示
在结果中高亮匹配关键词,提升可读性:
// 索引测试数据
itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f);
itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f);
SolrQuery query = new SolrQuery();
query.setQuery("Appliances");
query.setHighlight(true);
query.addHighlightField("category");
QueryResponse response = solrClient.query(query);
Map<String, Map<String, List<String>>> hitHighlightedMap = response.getHighlighting();
Map<String, List<String>> highlightedFieldMap = hitHighlightedMap.get("hm0001");
String highLightedText = highlightedFieldMap.get("category").get(0);
输出示例:Home <em>Appliances</em>
⚙️ 自定义高亮标签:
query.setHighlightSimplePre("<strong>");
query.setHighlightSimplePost("</strong>");
7. 搜索建议
7.1. 拼写检查
需手动配置拼写检查组件(参考官方文档)。使用 IndexBasedSpellChecker
的示例:
query.setQuery("hme"); // 错误拼写
query.set("spellcheck", "on");
QueryResponse response = solrClient.query(query);
SpellCheckResponse spellCheckResponse = response.getSpellCheckResponse();
String alternative = spellCheckResponse.getSuggestions().get(0).getAlternatives().get(0);
✅ 预期结果:alternative = "home"
7.2. 自动补全
配置 /suggest
请求处理器(参考官方文档):
SolrQuery query = new SolrQuery();
query.setRequestHandler("/suggest");
query.set("suggest", "true");
query.set("suggest.build", "true");
query.set("suggest.dictionary", "mySuggester");
query.set("suggest.q", "Hom"); // 输入前缀
QueryResponse response = solrClient.query(query);
List<String> suggestions = response.getSuggesterResponse()
.getSuggestedTerms()
.get("mySuggester");
8. 总结
本文仅触及 Solr 功能的冰山一角。作为成熟的搜索引擎,它还支持:
- 分布式集群部署
- 实时索引与近实时搜索
- 复杂的文本分析管道
- 空间搜索与地理围栏