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 功能的冰山一角。作为成熟的搜索引擎,它还支持:

  • 分布式集群部署
  • 实时索引与近实时搜索
  • 复杂的文本分析管道
  • 空间搜索与地理围栏

完整示例代码可在 GitHub 获取。对于生产环境,建议深入阅读官方文档,并关注性能调优与集群配置。


原始标题:Full-text Search with Solr