Article
第一章:Solr 概述与核心概念
1.1 什么是 Apache Solr
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| Apache Solr | 一个开源的、基于 Apache Lucene 构建的企业级全文搜索平台,提供 RESTful API,支持高性能索引与查询。 | Solr 本身不直接处理原始数据,需通过外部系统导入结构化或半结构化数据。 |
| 全文搜索引擎 | 能对文档中的全部文本内容进行索引和检索的系统,支持关键词匹配、模糊搜索、短语查询等。 | 与数据库 LIKE 查询不同,全文引擎基于倒排索引,效率更高、功能更丰富。 |
| RESTful 接口 | Solr 提供标准 HTTP 接口(GET/POST/PUT/DELETE),便于与任何编程语言集成。 | 所有操作均可通过 curl 或 Postman 测试,无需专用客户端。 |
| 可扩展性 | 支持水平扩展(SolrCloud)、插件机制、自定义请求处理器和分析器。 | 插件开发需熟悉 Java 和 Lucene API。 |
1.2 Solr 与 Lucene 的关系
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| Apache Lucene | 一个用 Java 编写的高性能、全文检索库,提供底层索引和搜索能力,但无网络接口或管理界面。 | Lucene 是库(Library),不能独立运行,需嵌入应用程序中使用。 |
| Apache Solr | 基于 Lucene 构建的完整搜索应用服务器,封装了 Lucene 功能并增加管理、分布式、API 等企业特性。 | Solr = Lucene + Web Server + Configuration + Admin UI + Distributed Features。 |
| 抽象层级差异 | Lucene 面向开发者,需手动管理 IndexWriter、Analyzer、QueryParser;Solr 面向运维与应用层,配置驱动。 | 若需极致性能控制或轻量集成,可直接使用 Lucene;若需快速部署搜索服务,选 Solr。 |
| 版本依赖 | Solr 严格依赖特定版本的 Lucene,升级 Solr 通常意味着 Lucene 也同步升级。 | 不建议混用不同版本的 Lucene JAR 与 Solr,可能导致兼容性问题。 |
1.3 Solr 核心特性与优势
| 特性名称 | 说明 | 注意事项 |
|---|---|---|
| 倒排索引(Inverted Index) | 将词项映射到包含该词的文档列表,实现快速关键词检索。 | 索引构建是一次性开销,查询速度极快,适合读多写少场景。 |
| 分面搜索(Faceting) | 在搜索结果基础上按字段(如分类、品牌、价格区间)动态聚合统计。 | Facet 性能受字段基数影响,高基数字段需谨慎使用。 |
| 高亮(Highlighting) | 在搜索结果中突出显示匹配关键词片段。 | 需在查询时启用 hl 参数,并指定要高亮的字段。 |
| 复制字段(CopyField) | 允许将一个字段内容复制到另一个字段,用于统一搜索入口(如 all_text)。 | 复制会增加索引体积和写入开销,应合理设计。 |
| 近实时搜索(NRT) | 文档提交后几秒内即可被搜索到,无需硬提交(hard commit)。 | 依赖 softCommit 配置,可能牺牲部分持久性换取响应速度。 |
| 插件化架构 | 支持自定义分词器、评分函数、请求处理器、缓存策略等。 | 插件需打包为 JAR 并放入 Solr 的 lib 目录或通过资源加载机制注入。 |
1.4 Solr 与 Elasticsearch 对比
| 对比维度 | Apache Solr | Elasticsearch | 注意事项 |
|---|---|---|---|
| 起源与社区 | 2006 年由 CNET 开源,后捐给 Apache,企业级应用历史悠久。 | 2010 年由 Shay Banon 创建,商业化推动迅速,社区活跃度高。 | Solr 更适合传统企业;ES 更受云原生和日志场景青睐。 |
| 架构模型 | 基于 ZooKeeper 实现 SolrCloud,强一致性。 | 内置集群协调机制(Zen Discovery),最终一致性。 | SolrCloud 依赖外部 ZK;ES 自包含但脑裂风险需配置防护。 |
| 配置方式 | XML 配置为主(schema.xml, solrconfig.xml)。 | JSON/YAML 配置,动态 mapping 支持更好。 | Solr 配置更显式、可控;ES 更灵活但易出错。 |
| 查询 DSL | 使用 Lucene 查询语法 + URL 参数,较简洁。 | 使用 JSON-based Query DSL,表达力更强但复杂。 | Solr 适合简单到中等复杂查询;ES 适合复杂嵌套聚合。 |
| 分析器与中文支持 | 依赖第三方分词器(如 IK、jieba),需手动集成。 | 同样需插件,但官方提供 analysis-icu 等基础支持。 | 两者中文处理能力相当,均需额外配置。 |
| 监控与运维 | Admin UI 功能全面,指标清晰。 | 需配合 Kibana 使用,生态整合好但组件多。 | Solr 单节点调试更直观;ES 适合 ELK 日志栈整体部署。 |
| 许可协议 | Apache License 2.0(完全开源,商业友好)。 | 历史版本 Apache 2.0,7.11+ 后部分功能改为 SSPL。 | 企业使用 ES 需注意许可证变更带来的合规风险。 |
第二章:环境搭建与基本配置
2.1 安装 Solr(单机模式)
| 步骤名称 | 操作细节 | 注意事项 |
|---|---|---|
| 下载 Solr | 访问 https://solr.apache.org/downloads.html,下载最新稳定版(如 solr-9.6.0.tgz)。 | 推荐使用官方 Apache 镜像站点,避免第三方修改版本。 |
| 解压安装包 | 在 Linux/macOS 执行:tar -xzf solr-9.6.0.tgz;Windows 可用 7-Zip 解压。 | 解压路径建议不含空格或中文,例如 /opt/solr。 |
| 验证 Java 环境 | 执行 java -version,确保已安装 JDK 11 或更高版本(Solr 9+ 要求 JDK 11+)。 | Solr 不支持 JRE,必须安装完整 JDK。 |
| 设置环境变量(可选) | 将 Solr 的 bin 目录加入 PATH:export PATH=$PATH:/opt/solr/bin | Windows 用户可将 bin 目录添加到系统 PATH。 |
| 验证安装完整性 | 进入解压目录,执行 ./bin/solr version 查看版本信息。 | 若提示权限错误,需 chmod +x bin/solr。 |
2.2 启动与验证 Solr 服务
| 步骤名称 | 操作细节 | 注意事项 |
|---|---|---|
| 启动 Solr(前台模式) | 执行 ./bin/solr start -f | -f 参数表示前台运行,便于查看日志,适合调试。 |
| 启动 Solr(后台模式) | 执行 ./bin/solr start | 默认监听 8983 端口,日志写入 server/logs。 |
| 指定端口启动 | 执行 ./bin/solr start -p 8984 | 多实例部署时需指定不同端口。 |
| 停止 Solr 服务 | 执行 ./bin/solr stop -all | -all 停止所有运行中的 Solr 实例。 |
| 验证服务是否运行 | 浏览器访问 http://localhost:8983/solr,或执行 curl http://localhost:8983/solr/admin/cores?action=STATUS | 若无法访问,检查防火墙、Java 版本或端口占用。 |
| 查看运行状态 | 执行 ./bin/solr status | 显示进程 ID、端口、运行时间等信息。 |
2.3 创建 Core / Collection
| 步骤名称 | 操作细节 | 注意事项 |
|---|---|---|
| 创建 Core(单机模式) | 执行 ./bin/solr create -c mycore | -c 指定 core 名称,自动创建同名目录和默认配置。 |
| 指定配置集创建 Core | 执行 ./bin/solr create -c mycore -n data_driven_schema_configs | -n 指定 configset,如 basic_configs、sample_techproducts_configs。 |
| 手动创建 Core 目录结构 | 在 server/solr/ 下新建 mycore 目录,复制 _default 配置,添加 core.properties 文件(name=mycore) | 适用于自定义 schema 和 solrconfig。 |
| 创建 Collection(SolrCloud) | 执行 ./bin/solr create_collection -c mycollection -shards 2 -replicationFactor 2 | 仅在 SolrCloud 模式下有效,需先启动 ZooKeeper。 |
| 删除 Core | 执行 ./bin/solr delete -c mycore | 删除后数据和配置不可恢复,请谨慎操作。 |
| 验证 Core 是否创建成功 | 访问 http://localhost:8983/solr/#/~cores/mycore | Admin UI 中应显示该 core 的概览信息。 |
2.4 管理控制台(Admin UI)简介
| 功能模块 | 说明 | 注意事项 |
|---|---|---|
| Dashboard(仪表盘) | 显示 Solr 版本、JVM 信息、系统负载、核心数量等全局状态。 | 刷新页面可实时更新指标。 |
| Logging(日志) | 查看服务器日志,支持按级别(INFO/WARN/ERROR)过滤。 | 日志文件实际存储在 server/logs/solr.log。 |
| Core Admin(Core 管理) | 列出所有 Core,支持创建、加载、卸载、重载、删除操作。 | 重载(Reload)可应用配置变更而无需重启。 |
| Query(查询界面) | 提供交互式查询表单,可设置 q、fq、fl、rows 等参数并查看 JSON 结果。 | 是学习 Solr 查询语法的最佳工具。 |
| Schema(模式浏览器) | 查看当前 Core 的字段定义、动态字段、复制字段等 Schema 信息。 | 仅当 managed-schema 启用时可编辑(需设置 mutable="true")。 |
| Files(配置文件浏览) | 浏览 solrconfig.xml、schema.xml、stopwords.txt 等配置文件内容。 | 不支持直接编辑,需手动修改后重载 Core。 |
| Cloud(集群视图) | 在 SolrCloud 模式下显示分片、副本、ZooKeeper 状态、集群拓扑。 | 单机模式下此标签页不可用或为空。 |
第三章:数据建模与 Schema 配置
3.1 Schema 基本结构
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| managed-schema 文件 | Solr 默认使用的 Schema 配置文件(替代旧版 schema.xml),支持运行时动态修改字段(需启用 mutable)。 | 文件位于 server/solr/<core>/conf/ 目录下。 |
| schemaFactory 配置 | 在 solrconfig.xml 中定义。 | mutable="true" 允许通过 Schema API 修改字段;设为 false 则只读。 |
| 字段模型组成 | 包含 fields(字段定义)、dynamicFields(动态字段)、uniqueKey(唯一键)、copyFields(复制字段)等部分。 | 所有字段必须有类型(type),且类型需在 fieldType 中预先定义。 |
| 字段类型(fieldType) | 定义字段的索引与查询行为,包括分词器(Tokenizer)、过滤器(Filter)、存储选项等。 | 修改 fieldType 不会影响已索引数据,需重建索引。 |
| Schema 版本 | managed-schema 文件顶部包含 version 属性,Solr 用其判断是否需要重新加载。 | 手动编辑后建议递增 version 值以确保生效。 |
3.2 字段(Field)定义与类型
字段属性:
| 字段属性 | 语法示例 | 用途说明 | 注意事项 |
|---|---|---|---|
| name | <field name="title" type="text_general" ... /> | 字段的唯一标识符,用于索引和查询。 | 名称不能包含空格或特殊字符(如 . / :)。 |
| type | type="string" 或 type="pint" | 指定字段的数据类型,决定如何分析、索引和排序。 | 必须引用已定义的 fieldType。 |
| indexed | indexed="true" | 是否对字段建立倒排索引,影响是否可被搜索。 | 若仅用于存储或排序,可设为 false 以节省空间。 |
| stored | stored="true" | 是否在索引中保存原始值,用于返回结果时展示。 | stored=false 时无法通过 fl 参数返回该字段。 |
| docValues | docValues="true" | 是否启用列式存储,用于排序、分面、函数查询。 | 对 string、date、numeric 类型强烈建议开启。 |
| multiValued | multiValued="true" | 是否允许多个值(如标签列表)。 | 单值字段设为 true 可能导致查询异常。 |
| required | required="true" | 是否为必填字段,索引文档时若缺失将报错。 | 仅在使用 Schema API 或严格校验时生效。 |
| default | default="unknown" | 字段缺失时的默认值。 | 仅对 stored 字段有效,且需在索引时显式处理。 |
常见内置字段类型示例:
string:不分词,精确匹配。text_general:通用文本,使用 StandardTokenizer + 小写过滤。pint/pfloat/pdate:点值(Point)数值/日期类型,支持高效范围查询。boolean:布尔值(true/false)。
3.3 动态字段(Dynamic Fields)
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| 动态字段定义 | 使用通配符(如 *_s、*_i、*_txt)匹配未显式声明的字段名。 | 规则按配置顺序匹配,建议将通用规则放在最后。 |
| 语法示例 | <dynamicField name="*_s" type="string" indexed="true" stored="true"/> 表示所有以 _s 结尾的字段自动视为 string 类型。 | — |
| 优势 | 无需预先声明所有字段,适合半结构化或 schema-less 场景。 | 过度依赖动态字段可能导致类型混乱,建议结合命名规范使用。 |
| 匹配优先级 | 显式 field 定义 > dynamicField(按配置顺序从上到下匹配第一个)。 | 若多个 dynamicField 匹配,只有第一个生效。 |
| 常见命名约定 | _s(string)、_i(int)、_l(long)、_d(double)、_dt(date)、_txt(text) | Apache Solr 示例配置中广泛采用此约定。 |
3.4 唯一键(Unique Key)与复制字段(Copy Field)
| 配置项 | 语法示例 | 用途说明 | 注意事项 |
|---|---|---|---|
| uniqueKey | <uniqueKey>id</uniqueKey> | 指定文档的唯一标识字段,用于更新、删除操作。 | 字段必须存在且值唯一;通常为 string 或 long 类型。 |
| copyField 源字段 | <copyField source="title" dest="all_text"/> 将 source 字段内容复制到 dest 字段。 | source 可为普通字段或动态字段。 | — |
| copyField 目标字段 | <copyField source="title" dest="all_text"/> 多个源可复制到同一目标,实现统一搜索入口。 | 目标字段必须已定义,且类型兼容(通常为 text)。 | — |
| 复制多字段 | 支持多个 <copyField> 标签,分别指定不同 source → dest 映射。常用于构建 all_text 字段,聚合 title、desc、tags 等。 | 复制会增加索引体积和写入开销,避免冗余复制。 | — |
| 限制条件 | 不支持跨 Core 复制;不支持在复制过程中修改值(如拼接、转换)。 | 如需复杂转换,应在索引前由客户端处理。 | |
| 启用复制字段 | 需在 solrconfig.xml 中启用 UpdateRequestProcessor(默认已启用)。 | 若未生效,检查是否禁用了相关处理器链。 |
第四章:文档索引操作
4.1 支持的数据格式(JSON/XML/CSV)
| 数据格式 | 语法特点与结构示例 | 用途说明 | 注意事项 |
|---|---|---|---|
| JSON | { "id": "1", "title": "Solr Guide", "price": 29.99 } | 最常用格式,结构清晰,支持嵌套对象(需配置 flattenMaps=false)。 | 字段名必须与 Schema 中定义一致;数值/布尔值无需引号。 |
| XML | <add><doc><field name="id">1</field></doc></add> | 传统格式,适合遗留系统集成。 | 根元素必须为 <add>,每个文档用 <doc> 包裹,字段用 <field> 表示。 |
| CSV | id,title,price\n1,"Solr Guide",29.99 | 适合批量导入表格数据,如从数据库导出。 | 首行为字段名;字符串含逗号需用双引号包裹;不支持嵌套结构。 |
| 格式自动识别 | Solr 根据 Content-Type 请求头判断格式:application/json → JSON、application/xml → XML、text/csv → CSV | 客户端需正确设置 HTTP Header。 | 若未指定或错误,可能导致解析失败。 |
| 其他格式 | 支持通过自定义 UpdateRequestProcessor 扩展(如 TSV、Avro)。 | 适用于特定数据管道场景。 | 需开发 Java 插件,非开箱即用。 |
4.2 使用 Solr API 添加文档
| 方法名称 | 语法(HTTP 请求) | 用途说明 | 代码示例(curl) | 注意事项 |
|---|---|---|---|---|
| 单文档添加 | POST /solr/<core>/update Content-Type: application/json | 向指定 Core 添加单个文档。 | curl -X POST http://localhost:8983/solr/mycore/update -H "Content-Type: application/json" -d '[{"id":"1","title":"Hello"}]' | 文档必须为 JSON 数组形式(即使单条)。 |
| 提交控制参数 | 在 URL 中添加 ?commit=true 或 ?commitWithin=5000 | 控制是否立即提交(使文档可搜索)。 | curl -X POST ".../update?commit=true" -d '[{...}]' | commit=true 影响性能,生产环境建议用 softCommit 或后台自动提交。 |
| 覆盖更新 | 使用相同 id 再次提交文档 | Solr 会自动覆盖旧文档(基于 uniqueKey)。 | 同上,确保 id 字段值不变。 | 必须已定义 uniqueKey,否则视为新文档。 |
| 返回结果解析 | 成功响应:{"responseHeader":{"status":0,"QTime":1}} | status=0 表示成功;非 0 表示错误(如字段类型不匹配)。 | 检查 QTime 可评估索引延迟。 | 错误信息在 responseHeader.error 中返回。 |
4.3 批量索引与原子更新
| 操作类型 | 语法与结构 | 用途说明 | 代码示例(JSON) | 注意事项 |
|---|---|---|---|---|
| 批量索引 | 发送包含多个文档的 JSON 数组 | 一次性索引大量数据,提升吞吐量。 | [{"id":"1","title":"A"},{"id":"2","title":"B"}] | 建议每批 100–1000 条,过大易导致内存溢出。 |
| 原子更新(Set) | {"id":"1","title":{"set":"New Title"}} | 仅更新指定字段,其他字段保留原值。 | curl -X POST ".../update" -d '[{"id":"1","price":{"set":39.99}}]' | 目标字段必须 stored="true" 且 docValues="true"(部分类型要求)。 |
| 原子更新(Inc) | {"id":"1","view_count":{"inc":1}} | 对数值字段执行原子递增。 | {"id":"101","score":{"inc":5}} | 仅支持 pint/pfloat/pdouble 等 Point 类型。 |
| 原子更新(Add) | {"id":"1","tags":{"add":["solr","search"]}} | 向 multiValued 字段追加值。 | {"id":"202","categories":{"add":["tech","tutorial"]}} | 若字段非 multiValued,操作将失败。 |
| 原子更新(Remove) | {"id":"1","tags":{"remove":["old_tag"]}} | 从 multiValued 字段移除指定值。 | {"id":"303","emails":{"remove":"old@example.com"}} | 值必须完全匹配(区分大小写)。 |
| 提交策略 | 结合 ?commitWithin=10000 实现延迟提交 | 平衡实时性与性能。 | POST /update?commitWithin=10000 | commitWithin 单位为毫秒。 |
4.4 删除文档(按 ID 或查询条件)
| 删除方式 | 语法(JSON 或 XML) | 用途说明 | 代码示例(curl + JSON) | 注意事项 |
|---|---|---|---|---|
| 按 ID 删除 | {"delete":{"id":"1"}} | 删除唯一键为 “1” 的文档。 | curl -X POST ".../update" -d '{"delete":{"id":"1"}}' | ID 值必须与 uniqueKey 字段类型一致(如 string)。 |
| 按多个 ID 删除 | {"delete":{"ids":["1","2","3"]}} | 批量删除多个文档。 | curl -X POST ".../update" -d '{"delete":{"ids":["10","20"]}}' | IDs 列表最多支持数千项,过多建议分批。 |
| 按查询条件删除 | {"delete":{"query":"category:obsolete"}} | 删除所有满足查询条件的文档。 | curl -X POST ".../update" -d '{"delete":{"query":"status:deleted"}}' | 查询语法与搜索一致;慎用 *:*(删除全部)。 |
| 组合删除 | 一个请求中包含多个 delete 操作 | 混合使用 ID 和 query 删除。 | {"delete":[ {"id":"1"}, {"query":"date:[* TO NOW-30DAYS]"} ]} | 操作按顺序执行。 |
| 提交控制 | 添加 ?commit=true 或依赖自动提交 | 控制删除是否立即生效。 | POST /update?commit=true -d '{"delete":{"query":"..."}}' | 未提交前,文档仍可被搜索到。 |
| 安全风险 | 无权限控制时,任意客户端可执行删除 | 生产环境应启用身份认证(如 Basic Auth)。 | — | 强烈建议在 solr.in.sh 中配置 SOLR_AUTH_TYPE。 |
第五章:查询与搜索功能
5.1 基本查询参数(q, fl, rows, start)
| 参数名称 | 语法示例 | 用途说明 | 代码示例(curl) | 注意事项 |
|---|---|---|---|---|
| q | q=title:Solr | 主查询条件,支持 Lucene 查询语法。 | curl "http://localhost:8983/solr/mycore/select?q=title:Solr" | 若未指定,默认 q=*:*(返回所有文档)。 |
| fl | fl=id,title,score | 指定返回字段列表(Field List)。 | curl ".../select?q=solr&fl=id,title,price" | 可包含函数字段(如 price:[* TO *]);* 表示返回所有 stored 字段。 |
| rows | rows=10 | 设置返回结果数量(分页大小)。 | curl ".../select?q=solr&rows=20" | 默认值通常为 10;过大影响性能和内存。 |
| start | start=20 | 设置结果偏移量,用于分页(第 (start/rows)+1 页)。 | curl ".../select?q=solr&rows=10&start=20" | 深度分页(start > 10000)性能急剧下降,建议用游标(cursorMark)替代。 |
| wt | wt=json | 指定响应格式(json/xml/csv/php等)。 | curl ".../select?q=solr&wt=xml" | 默认为 json;调试时可设为 csv 查看表格数据。 |
| indent | indent=true | 格式化 JSON 输出,便于阅读。 | curl ".../select?q=solr&indent=true" | 生产环境建议关闭以减少带宽。 |
5.2 查询解析器(Standard, DisMax, eDisMax)
| 解析器名称 | 调用方式(defType 参数) | 用途说明 | 代码示例(curl) | 注意事项 |
|---|---|---|---|---|
| Standard | defType=lucene(默认) | 使用标准 Lucene 语法,支持布尔操作、通配符、短语等。 | curl ".../select?q=title:(solr AND search)&defType=lucene" | 用户需熟悉 Lucene 语法;不处理拼写容错。 |
| DisMax | defType=dismax | 面向普通用户的简单查询,支持多字段搜索,忽略无效语法。 | curl ".../select?defType=dismax&q=solr search&qf=title^2 content" | qf 指定查询字段及权重;不支持复杂布尔逻辑。 |
| eDisMax | defType=edismax | DisMax 的增强版,支持更多高级功能(如近邻、提升规则)。 | curl ".../select?defType=edismax&q=solr&pf=title^5&qf=title content&boost=popularity" | 支持 pf(短语字段)、bq(提升查询)、boost 等参数。 |
| 关键参数 qf | qf=title^2 description | 在 DisMax/eDisMax 中指定查询字段及权重(^ 后为 boost 值)。 | 见上例 | 未指定 qf 时,仅搜索默认搜索字段(通常为 text 或 copyField 目标)。 |
| 关键参数 pf | pf=title^5 | 对匹配短语的文档额外加权(Phrase Boost)。 | curl ".../select?defType=edismax&q=solr guide&pf=title" | 仅当多个词连续出现时触发。 |
| mm(最小匹配) | mm=2<70% | 在 DisMax/eDisMax 中控制多词查询的最低匹配数或比例。 | mm=2 表示至少匹配2个词;mm=70% 表示至少匹配70%的词。 | 防止因一词不匹配导致无结果。 |
5.3 过滤查询(fq)与分页
| 功能名称 | 语法示例 | 用途说明 | 代码示例(curl) | 注意事项 |
|---|---|---|---|---|
| fq(过滤查询) | fq=category:books | 在主查询结果上应用过滤,不影响评分(score)。 | curl ".../select?q=solr&fq=in_stock:true&fq=price:[0 TO 50]" | 可多次使用 fq 实现多条件”AND”过滤。 |
| fq 性能优势 | — | fq 结果可被 Filter Cache 缓存,重复查询极快。 | — | 高频过滤字段应开启 docValues 并使用 fq。 |
| 分页(rows+start) | rows=10&start=0 | 实现传统分页(第1页:start=0;第2页:start=10)。 | curl ".../select?q=solr&rows=10&start=10" | start 越大,性能越差(需跳过前面文档)。 |
| 游标分页(深度分页) | cursorMark=*&sort=id asc | 使用 cursorMark 替代 start,实现高效深度遍历。 | 首次:curl ".../select?q=solr&sort=id asc&cursorMark=*&rows=10" | 必须指定唯一且有序的 sort 字段(如 id)。 |
| — | — | — | 后续:用返回的 nextCursorMark 替换 * | — |
| 排序字段要求 | sort=price asc, id desc | 排序字段必须启用 docValues="true"。 | — | 否则报错:“can not sort on unindexed field”。 |
5.4 高亮(Highlighting)与分面(Faceting)
| 功能名称 | 参数与语法 | 用途说明 | 代码示例(curl) | 注意事项 |
|---|---|---|---|---|
| 高亮启用 | hl=true | 在结果中返回匹配关键词的高亮片段。 | curl ".../select?q=solr&hl=true&hl.fl=content" | 必须指定 hl.fl(要高亮的字段)。 |
| 高亮字段 | hl.fl=title,content | 指定哪些字段需要高亮。 | — | 字段必须 indexed="true"。 |
| 高亮标签 | hl.simple.pre=<em>&hl.simple.post=</em> | 自定义高亮前缀/后缀(默认为 <em> </em>)。 | curl ".../select?q=solr&hl=true&hl.fl=content&hl.simple.pre=<em>&hl.simple.post=</em>" | 可用于前端样式定制。 |
| 分面启用 | facet=true | 返回按字段值聚合的统计信息(如分类计数)。 | curl ".../select?q=solr&facet=true&facet.field=category" | 常用于筛选导航(Filter Navigation)。 |
| 分面字段 | facet.field=category | 对单值字符串字段进行分面。 | — | 字段应为 string 类型且 docValues="true"。 |
| 范围分面 | facet.range=price&f.price.facet.range.start=0&... | 对数值/日期字段按区间分面。 | curl ".../select?q=solr&facet=true&facet.range=price&f.price.facet.range.start=0&f.price.facet.range.end=100&f.price.facet.range.gap=10" | 需指定 start/end/gap。 |
| 分面限制 | facet.limit=5 | 限制返回的分面值数量(默认100)。 | — | 可结合 facet.sort=count 按频次排序。 |
5.5 排序、相关性评分与函数查询
| 功能名称 | 语法示例 | 用途说明 | 代码示例(curl) | 注意事项 |
|---|---|---|---|---|
| 基础排序 | sort=price asc | 按字段升序/降序排列结果。 | curl ".../select?q=solr&sort=popularity desc, id asc" | 多字段排序用逗号分隔。 |
| 相关性评分(score) | sort=score desc | 按 Solr 计算的相关性得分排序(默认)。 | — | score 由 TF-IDF、字段 boost 等因素决定。 |
| 函数查询(排序) | sort=product(popularity,2) desc | 使用函数动态计算排序值。 | curl ".../select?q=solr&sort=div(view_count,10) desc" | 支持 math 函数(add, sub, mul, div, log, pow 等)。 |
| 函数查询(字段) | fl=id,score,my_score:sum(popularity,10) | 在返回字段中添加函数计算结果。 | — | 函数字段可用于排序、分面、高亮。 |
| 查询时字段提升 | bq=popularity:[9 TO *]^5 | 在 eDisMax 中对高人气文档额外加权。 | curl ".../select?defType=edismax&q=solr&bq=popularity:[9 TO *]^5" | bq 不影响主查询匹配,只影响评分。 |
| 自定义评分(bf) | bf=recip(abs(ms(NOW, publish_date)),3.16e-11,1,1) | 使用 bf(boost function)基于函数值提升评分。常用于”新鲜度”加权(越新得分越高)。 | — | recip 函数常用于将时间差转为衰减分数。 |
| 调试评分 | debugQuery=true | 返回评分详细计算过程(explain)。 | curl ".../select?q=solr&debugQuery=true" | 用于优化查询相关性,但开销大,勿用于生产高频查询。 |
第六章:高级功能与扩展
6.1 近实时索引(NRT)
| 概念/操作名称 | 配置或调用方式 | 用途说明 | 代码示例 / 配置片段 | 注意事项 |
|---|---|---|---|---|
| softCommit | 在 solrconfig.xml 中配置 <autoSoftCommit><maxTime>1000</maxTime></autoSoftCommit> | 文档提交后约1秒内可被搜索(不刷盘),实现近实时可见性。 | <autoSoftCommit><maxTime>2000</maxTime></autoSoftCommit> | softCommit 不保证持久化,进程崩溃可能丢失数据。 |
| hardCommit | <autoCommit><maxTime>15000</maxTime></autoCommit> | 定期将索引写入磁盘并刷新,确保数据持久化。 | — | 影响性能,频率不宜过高。 |
| 实时 Get(RealTime Get) | 使用 /get 接口:GET /solr/mycore/get?id=1 | 即使未 softCommit,也可通过唯一键获取最新文档(需启用 rtg)。 | curl "http://localhost:8983/solr/mycore/get?id=1" | 需在 solrconfig.xml 中启用 <requestHandler name="/get" class="solr.RealTimeGetHandler">。 |
| NRT 限制 | — | NRT 仅适用于已分配 segment 的文档;大量并发写入可能延迟可见。 | — | 不适用于强一致性要求场景。 |
| 提交策略建议 | 索引时使用 ?commitWithin=5000 而非频繁 commit=true | 平衡实时性与系统负载。 | POST /update?commitWithin=5000 -d '[{...}]' | commitWithin 触发 softCommit(若 autoSoftCommit 启用)。 |
6.2 自动建议(Suggester / Auto-suggest)
| 组件/参数名 | 配置位置与语法 | 用途说明 | 配置示例(solrconfig.xml) | 注意事项 |
|---|---|---|---|---|
| Suggester 类型 | 在 solrconfig.xml 的 <searchComponent> 中定义 | 提供搜索词自动补全建议。 | <searchComponent class="solr.SuggestComponent" name="suggest"> | 常用实现:AnalyzingInfixLookupFactory(支持中缀匹配)。 |
| Lookup Factory | lookupImpl="AnalyzingInfixLookupFactory" | 支持任意位置匹配(如”solr”匹配”Apache Solr Guide”)。 | <lst name="suggester"><str name="lookupImpl">AnalyzingInfixLookupFactory</str>...</lst> | 需配合高亮和权重字段使用。 |
| 字段来源 | field="title_suggest" | 指定用于构建建议词典的字段。 | <str name="field">product_name</str> | 字段应为不分词 string 或专用 suggest 字段。 |
| 权重字段 | weightField="popularity" | 根据字段值对建议排序(如点击量高的排前)。 | <str name="weightField">view_count</str> | weightField 必须为数值类型且 docValues="true"。 |
| 构建词典 | 手动触发:POST /solr/mycore/suggest?suggest.build=true | 首次使用前需构建建议索引。 | curl -X POST "http://localhost:8983/solr/mycore/suggest?suggest.build=true" | 数据变更后需重新 build(或配置自动 reload)。 |
| 查询建议 | GET /solr/mycore/suggest?suggest.q=sol | 获取以”sol”开头或包含的建议列表。 | curl "http://localhost:8983/solr/mycore/suggest?suggest.q=sol&wt=json" | 返回结果包含 term、weight、payload 等字段。 |
| 高亮建议 | suggest.highlight=<em> | 在建议词中高亮匹配部分。 | &suggest.highlight=<em> | 前端需解析并渲染高亮标签。 |
6.3 拼写检查(Spell Check)
| 组件/参数名 | 配置位置与语法 | 用途说明 | 配置示例(solrconfig.xml) | 注意事项 |
|---|---|---|---|---|
| SpellCheckComponent | <searchComponent class="solr.SpellCheckComponent" name="spellcheck"> | 提供拼写纠错建议(如”solor” → “solr”)。 | — | 需在 requestHandler 中引用。 |
| 字典构建方式 | spellcheck.dictionary=default field="spellcheck_field" | 从指定字段提取词项构建拼写字典。 | <str name="field">title</str> | 字段应为 text 类型,经分词处理。 |
| 字典类型 | classname="solr.DirectSolrSpellChecker" | 直接使用索引中的词项,无需额外字典文件。 | — | 推荐用于动态内容;静态字典可用 FileBasedSpellChecker。 |
| 启用拼写检查 | 在查询中添加 spellcheck=true | 返回拼写建议。 | curl ".../select?q=solor&spellcheck=true&spellcheck.collate=true" | collate=true 自动生成修正后的查询。 |
| 返回结果字段 | response.spellcheck.suggestions | 包含原始词、建议词、频率等信息。 | — | 建议数由 spellcheck.count 控制(默认1)。 |
| 自动触发条件 | spellcheck.onlyMorePopular=true | 仅当建议词频高于原词时才返回。 | — | 避免低质量建议干扰用户。 |
| 性能影响 | — | 拼写检查增加查询开销,尤其在大索引上。 | — | 建议缓存字典或限制查询频率。 |
6.4 地理空间搜索(Spatial Search)
| 功能/参数名 | 语法与配置 | 用途说明 | 代码示例 / 配置 | 注意事项 |
|---|---|---|---|---|
| 字段类型 | fieldType name="location" class="solr.LatLonPointSpatialField" | 存储经纬度坐标(如 "40.714,-74.006")。 | <fieldType name="location" class="solr.LatLonPointSpatialField" docValues="true"/> | Solr 6+ 推荐使用 LatLonPointSpatialField(基于 Lucene Point)。 |
| 距离查询 | q={!geofilt pt=40.714,-74.006 sfield=store_location d=10} | 查找距离指定点10公里内的文档。 | curl ".../select?q={!geofilt pt=45.15,-93.85 sfield=location d=5}" | d 单位为千米;需字段为 spatial 类型。 |
| 边界框查询 | q={!bbox pt=40.714,-74.006 sfield=store_location d=10} | 使用矩形边界框近似过滤(比 geofilt 快)。 | — | 精度略低,适合初筛。 |
| 排序按距离 | sort=geodist(store_location,40.714,-74.006) asc | 按距离升序排列结果。 | curl ".../select?q=*:*&sort=geodist(location,45.15,-93.85) asc&fl=id,geodist:geodist(location,45.15,-93.85)" | geodist() 函数返回距离(千米)。 |
| 多边形查询 | q={!field f=location}Intersects(POLYGON((...))) | 判断位置是否在多边形区域内(WKT 格式)。 | Intersects(POLYGON((-74.0 40.7, -73.9 40.7, -73.9 40.8, -74.0 40.8, -74.0 40.7))) | 需 Solr 7+ 支持;性能低于圆形查询。 |
| 索引要求 | — | 地理字段必须 indexed="true" 且使用 spatial fieldType。 | — | 不支持普通 string 字段存储坐标。 |
| 单位与精度 | — | LatLonPoint 支持亚米级精度;距离计算使用 Haversine 公式。 | — | 高纬度地区距离误差略大。 |
第七章:SolrCloud 分布式架构
7.1 SolrCloud 架构原理
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| SolrCloud | Solr 的分布式模式,支持水平扩展、高可用、自动故障转移和负载均衡。 | 需依赖外部 ZooKeeper 集群(或内嵌模式,仅用于测试)。 |
| 集群拓扑 | 由多个 Solr 节点组成,每个节点运行相同代码,通过 ZooKeeper 协调状态。 | 所有节点对等(无主从),任一节点可接收请求并路由到正确分片。 |
| Collection | 逻辑上的完整索引单元,由一个或多个 Shard 组成。 | 用户操作对象是 Collection,而非单个 Core。 |
| Shard(分片) | Collection 的水平分区,每个 Shard 存储部分文档数据。 | 文档通过路由规则(默认 hash(id))分配到特定 Shard。 |
| Replica(副本) | Shard 的复制实例,提供高可用和读负载分担。 | 每个 Shard 至少应有 2 个 Replica(1 Leader + 1+ Follower)。 |
| Leader 选举 | 每个 Shard 自动选举一个 Leader,负责写入协调和副本同步。 | Leader 失效后,ZooKeeper 触发新选举,过程通常 < 30 秒。 |
| 无单点写入 | 客户端可向任意 Solr 节点写入,节点自动转发到对应 Shard 的 Leader。 | 写入路径:Client → Any Node → Shard Leader → Replicas。 |
7.2 ZooKeeper 集合与作用
| 功能/组件 | 说明 | 注意事项 |
|---|---|---|
| 配置存储 | 所有 Collection 的配置文件(schema.xml, solrconfig.xml 等)集中存于 ZK。 | 修改配置需上传新 configset 到 ZK,再 reload 或创建新 Collection。 |
| 集群状态管理 | ZK 维护活跃节点列表、Shard/Replica 分布、Leader 位置等元数据。 | Solr 节点启动时向 ZK 注册;宕机后 ZK 标记其为离线。 |
| 分布式协调 | 提供原子操作、监听机制(Watch),用于 Leader 选举和状态同步。 | ZK 是 CP 系统(强一致),网络分区时可能不可用。 |
| 启动集成方式 | 启动 Solr 时指定 ZK 地址:./bin/solr start -cloud -z localhost:2181 | -cloud 参数启用 SolrCloud 模式;-z 指定 ZK 连接串。 |
| 内嵌 ZooKeeper | 用于开发测试:./bin/solr start -cloud -p 8983 | 自动启动内嵌 ZK(端口 9983),不适用于生产环境。 |
| ZK 数据结构 | /collections/<name>/... /live_nodes /overseer/queue | 不建议手动修改 ZK 节点数据,应通过 Solr API 操作。 |
| ZK 高可用要求 | 生产环境 ZK 应为奇数节点集群(3/5/7),避免脑裂。 | ZK 集群本身需独立部署、监控和备份。 |
7.3 分片(Sharding)与副本(Replication)
| 操作/参数名 | 语法或配置方式 | 用途说明 | 代码示例(命令行) | 注意事项 |
|---|---|---|---|---|
| 创建分片 Collection | ./bin/solr create_collection -c mycoll -shards 3 -replicationFactor 2 | 创建含 3 个 Shard、每个 Shard 2 个 Replica 的 Collection。 | — | 总节点数 ≥ shards × replicationFactor(本例需 ≥6 节点)。 |
| 路由规则 | 默认:route=hash(id) 自定义:router=implicit | 控制文档分配到哪个 Shard。 | implicit 路由需显式指定 shard key(如 id=shard1!doc1)。 | hash 路由无法控制数据分布;implicit 适合按业务分区。 |
| 增加分片 | 不支持动态增加 Shard(需重建 Collection 或使用 split shard API)。 | 扩容时需提前规划 Shard 数量。 | Solr 7+ 支持 SplitShard API,但操作复杂且需停写。 | 建议初始 Shard 数 = 预期最大节点数。 |
| 增加副本 | POST /admin/collections?action=ADDREPLICA&collection=mycoll&shard=shard1 | 为指定 Shard 添加新 Replica。 | curl ".../admin/collections?action=ADDREPLICA&collection=mycoll&shard=shard1" | 需确保目标节点有足够资源。 |
| 副本同步机制 | Leader 接收写入后,异步将更新发送给所有 Replica。 | 保证数据一致性(最终一致)。 | — | 网络延迟可能导致短暂不一致。 |
| 读负载均衡 | 查询请求自动轮询该 Shard 的所有 Replica。 | 提升查询吞吐量。 | — | 可通过 preferLocalShards=true 优先本地副本。 |
| 副本状态 | ACTIVE / DOWN / RECOVERING | 在 Admin UI Cloud → Graph 中可视化。 | — | DOWN 副本不参与查询;RECOVERING 表示正在同步数据。 |
7.4 集群管理与故障恢复
| 操作/功能 | 说明 | 命令或 API 示例 | 注意事项 |
|---|---|---|---|
| 节点扩容 | 启动新 Solr 节点并连接同一 ZK 集群 | ./bin/solr start -cloud -p 8984 -z zk1:2181,zk2:2181,zk3:2181 | 新节点自动加入集群,但不会自动迁移数据(需手动 ADDREPLICA)。 |
| 节点缩容 | 先移除该节点上的 Replica,再停止服务 | POST /admin/collections?action=DELETEREPLICA&collection=mycoll&shard=shard1&replica=core_node3 | 直接 kill 节点会导致 ZK 标记为 DOWN,可能触发不必要的选举。 |
| Leader 重新选举 | 自动触发(Leader 宕机)或手动触发 | POST /admin/collections?action=RELOAD&collection=mycoll(间接触发) | 手动强制选举需操作 ZK,不推荐。 |
| 集群状态查看 | Admin UI → Cloud → Tree / Graph | 或通过 API:GET /admin/collections?action=CLUSTERSTATUS | Graph 视图直观显示 Shard/Replica 分布及状态。 |
| 故障恢复流程 | 1. ZK 检测节点离线;2. 触发新 Leader 选举;3. 查询自动路由到存活 Replica | — | 恢复时间取决于 ZK session timeout(默认 30 秒)。 |
| 数据恢复 | 新 Replica 启动后自动从 Leader 同步索引快照 | — | 首次同步可能耗时较长(取决于索引大小)。 |
| Overseer 角色 | ZK 中的特殊队列处理器,负责集群变更操作(如创建 Collection) | 若 Overseer 宕机,ZK 会选举新 Overseer | 不应手动干预 Overseer 节点。 |
| 监控关键指标 | ZK 连接状态、Replica 状态、Leader 切换频率、写入延迟 | 使用 Prometheus + Solr Exporter 或 JMX | 建议设置告警:Replica DOWN > 5 分钟。 |
第八章:性能调优与监控
8.1 索引性能优化
| 优化项 | 配置方式或操作 | 用途说明 | 示例 / 建议值 | 注意事项 |
|---|---|---|---|---|
| 批量提交(Batch Commit) | 减少 commit 频率,使用 commitWithin 或后台 autoCommit | 降低 I/O 和合并开销,提升吞吐量。 | 每批 1000–5000 文档;autoCommit maxTime=15000(15秒) | 避免频繁 hard commit;softCommit 可用于 NRT。 |
| 并发索引线程 | 客户端多线程并发 POST 到不同 Solr 节点 | 充分利用集群写入能力。 | 使用线程池(如 Java ExecutorService)并行发送请求。 | 单节点写入并发不宜过高(建议 ≤ CPU 核数)。 |
| 禁用不必要的字段 | 设置 indexed="false"、stored="false"、docValues="false"(按需) | 减少索引体积和写入开销。 | 仅对搜索/排序/返回必需的字段启用对应属性。 | docValues 对分面/排序至关重要,勿盲目关闭。 |
| 合并策略(Merge Policy) | 在 solrconfig.xml 中调整 <mergePolicyFactory> | 控制段(Segment)合并频率与大小。 | TieredMergePolicy:maxMergeAtOnce=10, segmentsPerTier=10 | 过度合并影响写入;过少合并影响查询性能。 |
| 禁用实时 Get(若不用) | 移除或注释 solrconfig.xml 中的 /get RequestHandler | 减少事务日志(tlog)写入开销。 | — | 若依赖 NRT Get,不可禁用。 |
| 使用 Point 类型 | 用 pint/pfloat/pdate 替代旧 numericField | Point 字段索引更快、存储更省、范围查询更高效。 | <field name="price" type="pfloat" ... /> | Solr 6+ 推荐全面使用 Point 类型。 |
| 禁用高亮/拼写等组件 | 索引阶段不涉及,但 schema 中避免冗余 copyField | 减少索引时的字段复制和分析开销。 | 仅在必要时使用 copyField 构建 search_all 字段。 | 复制字段会显著增加索引时间和体积。 |
8.2 查询缓存与 Filter Cache
| 缓存类型 | 配置位置(solrconfig.xml) | 用途说明 | 默认配置 / 建议值 | 注意事项 |
|---|---|---|---|---|
| FilterCache | <filterCache class="solr.FastLRUCache" size="512" initialSize="512" autowarmCount="0"/> | 缓存 fq(过滤查询)结果,加速重复过滤。 | size=512(可增至数千,视内存而定) | 高频过滤字段(如 category、status)受益最大。 |
| QueryResultCache | <queryResultCache class="solr.LRUCache" size="512" initialSize="512" autowarmCount="0"/> | 缓存完整查询结果(含文档 ID 列表)。 | 适用于重复相同 q+fq+sort 的场景 | 若结果集大或变化频繁,命中率低,可关闭。 |
| DocumentCache | <documentCache class="solr.LRUCache" size="512" initialSize="512" autowarmCount="0"/> | 缓存已加载的文档(用于 stored 字段返回)。 | size 应 ≥ max(rows) × 并发查询数 | 内存消耗大,但能显著减少磁盘 I/O。 |
| FieldValueCache | 自动创建(用于 faceting、sorting) | 缓存 docValues 字段值。 | 无需显式配置 | 依赖 docValues="true";大基数字段慎用分面。 |
| 缓存清除策略 | autowarmCount="4" | 节点重启或重载 Core 时预热缓存(取最近 N 个查询重建缓存)。 | autowarmCount=0 表示不预热;生产环境建议设为 4–16 | 预热会延长启动时间,但提升冷启动后性能。 |
| 缓存监控 | Admin UI → Plugins / Stats → cache 相关指标 | 查看命中率(hitRatio)、大小、驱逐次数。 | hitRatio > 0.7 表示有效;< 0.3 可考虑调小或关闭 | 低命中率缓存浪费内存,应优化或禁用。 |
| 禁用缓存 | 将 size 设为 0 或注释对应 cache 配置 | 节省内存,适用于查询高度随机场景。 | — | 不推荐完全关闭 FilterCache(除非内存极度紧张)。 |
8.3 JVM 与 GC 调优建议
| 调优项 | JVM 参数示例 | 用途说明 | 建议值 / 说明 | 注意事项 |
|---|---|---|---|---|
| 堆内存(Heap) | -Xms8g -Xmx8g | 设置初始与最大堆内存,避免动态扩容开销。 | 生产环境建议 Xms = Xmx;不超过物理内存的 70% | 过大堆导致 GC 停顿长;过小导致频繁 GC。 |
| GC 算法 | -XX:+UseG1GC | 使用 G1 垃圾回收器(Solr 官方推荐)。 | Solr 7+ 默认使用 G1;避免使用 CMS(已废弃) | G1 适合大堆(>4GB)且要求停顿可控。 |
| GC 日志 | -Xlog:gc*:gc.log:time,tags | 记录 GC 行为,用于分析停顿原因。 | 必须开启用于性能诊断 | 日志文件需定期轮转,避免占满磁盘。 |
| 直接内存(Off-Heap) | -XX:MaxDirectMemorySize=1g | 限制 Netty/NIO 使用的堆外内存。 | 默认无限制,可能 OOM;建议设为 1–2GB | Solr 使用堆外内存缓存部分索引数据。 |
| 禁用显式 GC | -XX:+DisableExplicitGC | 防止 System.gc() 调用触发 Full GC。 | 强烈建议开启 | 某些库可能调用 System.gc(),导致意外停顿。 |
| 元空间(Metaspace) | -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m | 控制类元数据内存。 | 避免默认无上限导致系统内存耗尽 | 插件多或动态类加载场景需调大。 |
| GC 停顿目标 | -XX:MaxGCPauseMillis=200 | G1 的期望最大停顿时间(毫秒)。 | 默认 200ms;可尝试 100–300ms 之间调整 | 实际停顿可能超出目标,需结合日志分析。 |
| 监控工具 | jstat -gcutil <pid> 5s / jcmd <pid> GC.run | 实时查看 GC 状态或手动触发 GC(测试用)。 | — | 生产环境避免手动触发 GC。 |
8.4 日志分析与监控指标
| 监控类别 | 关键指标 / 日志内容 | 采集方式 | 用途说明 | 注意事项 |
|---|---|---|---|---|
| 请求延迟 | QTime(查询时间)、updateTime(索引时间) | Solr 日志(INFO 级别)或 responseHeader.QTime | 识别慢查询或写入瓶颈 | QTime > 1000ms 应重点分析。 |
| 错误率 | ERROR/WARN 日志数量、HTTP 5xx 响应 | grep "ERROR" server/logs/solr.log | 发现配置错误、资源不足、网络问题等 | 应设置日志告警(如 ELK + Alerting)。 |
| 缓存命中率 | filterCache.hitRatio、queryResultCache.hitRatio | Admin UI → Metrics 或 JMX | 评估缓存有效性 | 低命中率需优化查询模式或缓存配置。 |
| JVM 状态 | Heap usage、GC count/time、thread count | JMX(com.sun.management.*)或 Prometheus Exporter | 预防 OOM、线程阻塞等问题 | 堆使用持续 > 80% 需扩容或调优。 |
| 索引大小与段数 | numDocs、maxDoc、segmentCount | Admin UI → Core → Overview 或 Luke 工具 | 段数过多影响查询性能;文档数异常增长可能数据重复 | 定期 forceMerge 可减少段数(需停写)。 |
| ZooKeeper 连接状态 | zkConnected、zkClientTimeout | Solr 日志中 “ZooKeeper client connected” / “disconnected” | 确保 SolrCloud 集群协调正常 | ZK 断连会导致写入失败、Leader 选举异常。 |
| 磁盘与 I/O | 索引目录磁盘使用率、iostat 输出 | df -h、iostat -x 1 | 避免磁盘写满导致服务中断 | 建议索引目录使用 SSD。 |
| 监控集成方案 | Prometheus + Grafana + Solr Exporter | 部署 solr-exporter,暴露 /metrics 端点 | 可视化展示 QPS、延迟、缓存、JVM 等核心指标 | 官方提供 Grafana Dashboard 模板。 |
第九章:与 Spring Boot 集成
9.1 Spring Data Solr 依赖配置
| 配置项 | 配置方式 | 用途说明 | 示例代码 / 配置值 | 注意事项 |
|---|---|---|---|---|
| Maven 依赖 | 在 pom.xml 中添加 spring-boot-starter-data-solr | 引入 Spring Data Solr 支持。 | <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-solr</artifactId></dependency> | Spring Boot 2.x 使用此依赖;3.x 起官方已移除,需改用 SolrJ 或第三方库。 |
| Gradle 依赖 | implementation 'org.springframework.boot:spring-boot-starter-data-solr' | 同上,适用于 Gradle 项目。 | — | 注意版本兼容性(Solr 8+ 建议 Spring Boot ≤ 2.7)。 |
| Solr 服务器地址配置 | application.properties 或 application.yml | 指定 Solr 实例地址(单机或 Cloud)。 | solr.host=http://localhost:8983/solr 或 solr.zk-host=localhost:2181 | 单机模式用 host;Cloud 模式用 zk-host。 |
| SolrTemplate Bean | 自动配置(若依赖和配置正确) | 提供底层 Solr 操作模板(如 query、saveBean 等)。 | @Autowired private SolrTemplate solrTemplate; | 若需多数据源,需手动配置多个 SolrTemplate。 |
| 连接超时设置 | 通过 SolrClient 配置(需自定义 Bean) | 控制连接/读取超时,避免请求挂起。 | HttpSolrClient.Builder builder = new HttpSolrClient.Builder("http://..."); builder.withConnectionTimeout(5000); | 默认超时较长(数秒),生产环境应显式设置。 |
| Spring Boot 版本限制 | Spring Boot 2.7 是最后一个官方支持 spring-data-solr 的版本 | Spring Boot 3.x 不再维护该模块。 | 如需在 3.x 使用,可考虑:直接使用 Apache SolrJ 或使用第三方库(如 solr-spring-boot-starter) | 建议新项目优先评估 SolrJ + 自定义封装。 |
9.2 实体类映射与注解
| 注解名称 | 语法示例 | 用途说明 | 示例代码 | 注意事项 |
|---|---|---|---|---|
| @SolrDocument | @SolrDocument(collection = "products") | 标记实体类对应 Solr Collection。 | @SolrDocument(collection = "books") public class Book { ... } | collection 可省略,默认为类名转小写。 |
| @Id | @Id private String id; | 指定唯一键字段(对应 Schema 中 uniqueKey)。 | — | 字段类型必须与 Solr 中 uniqueKey 类型一致(通常为 String)。 |
| @Field | @Field("title_s") private String title; | 映射 Java 字段到 Solr 字段名。 | @Field("price_f") private Float price; | 若 Solr 字段名与 Java 字段名相同,可省略 value。 |
| @Dynamic | @Dynamic private Map<String, Object> dynamicFields; | 支持动态字段(匹配 dynamicField 规则)。 | — | 仅支持 Map<String, Object> 类型;写入时自动按 key 匹配动态规则。 |
| @Indexed | (已弃用) | 旧版注解,现由 @Field 替代。 | — | 不建议使用。 |
| 字段类型兼容性 | Java 类型 ↔ Solr 类型 | 确保类型匹配,避免序列化错误。 | String ↔ string/text、Integer/Long ↔ pint/plong、Date ↔ pdate、Boolean ↔ boolean | 数值类型推荐使用包装类(Integer 而非 int),避免 null 问题。 |
| 多值字段 | @Field("tags") private List<String> tags; | 映射 multiValued 字段。 | — | 必须使用 Collection 类型(List/Set),不能是数组。 |
9.3 Repository 接口开发
| 方法命名规则 | 接口方法声明 | 用途说明 | 自动生成的查询逻辑 | 注意事项 |
|---|---|---|---|---|
| findBy + 字段名 | List<Book> findByTitle(String title); | 精确匹配指定字段。 | q=title:"value" | 字段必须 indexed="true"。 |
| findBy + 字段名 + Containing | List<Book> findByAuthorContaining(String author); | 模糊匹配(类似 SQL LIKE)。 | q=author:*value*(需字段支持通配符) | 性能较差,建议用 text 类型 + 分词。 |
| findBy + 多字段 | List<Book> findByTitleAndAuthor(String title, String author); | 多条件 AND 查询。 | q=title:"t" AND author:"a" | 字段顺序不影响结果。 |
| findBy + 字段名 + Between | List<Book> findByPriceBetween(Float min, Float max); | 范围查询。 | q=price:[min TO max] | 字段需为数值类型(pfloat/pint)。 |
| findAll | Page<Book> findAll(Pageable pageable); | 分页查询所有文档。 | q=*:* + start/rows | 需配合 Pageable 使用。 |
| deleteBy + 字段名 | void deleteByCategoryId(String categoryId); | 按条件删除文档。 | delete query: category_id:"value" | 需调用 solrTemplate.commit() 才生效。 |
| 自定义 @Query | @Query("title:?0 OR author:?0") List<Book> searchByKeyword(String keyword); | 使用原生 Solr 查询语法。 | 直接执行 q=title:keyword OR author:keyword | ?0 表示第一个参数;支持占位符。 |
| 返回高亮结果 | (不直接支持,需结合 SolrTemplate) | Repository 无法直接返回高亮片段。 | — | 高亮需在 Service 层通过 SolrTemplate 实现(见 9.4)。 |
9.4 自定义查询与高亮实现
| 功能 | 实现方式 | 用途说明 | 示例代码(Service 层) | 注意事项 |
|---|---|---|---|---|
| 构建查询对象 | 使用 SimpleQuery / Criteria | 组装复杂查询条件。 | Criteria criteria = new Criteria("title").contains("solr"); SimpleQuery query = new SimpleQuery(criteria); | Criteria 支持 and/or/not、between、fuzzy 等操作。 |
| 执行带高亮的查询 | solrTemplate.queryForPage(query, Book.class, highlightOptions) | 返回分页结果及高亮片段。 | HighlightOptions opts = new HighlightOptions(); opts.addField("title").setSimplePrefix("<em>").setSimplePostfix("</em>"); HighlightPage<Book> page = solrTemplate.queryForHighlightPage(query, Book.class, opts); | 需启用 hl=true 并指定 hl.fl。 |
| 解析高亮结果 | page.getHighlighted() | 获取每个文档的高亮字段内容。 | for (HighlightEntry<Book> entry : page.getHighlighted()) { Map<String, List<String>> highlights = entry.getHighlights(); } | highlights.get("title") 返回高亮片段列表。 |
| 函数查询 | query.addFilterQuery(new SimpleFilterQuery("score:product(popularity,2)")); | 在查询中使用函数(如排序、评分)。 | — | 函数需符合 Solr 语法;建议先在 Solr Admin 测试。 |
| 分面查询 | query.setFacetOptions(new FacetOptions().addFacetOnField("category")); | 获取分面统计结果。 | FacetPage<Book> facetPage = solrTemplate.queryForFacetPage(query, Book.class, facetOptions); | 分面字段需为 string 且 docValues="true"。 |
| 原生 SolrQuery | SolrQuery solrQuery = new SolrQuery("q=*:*&hl=true&hl.fl=content"); | 完全控制查询参数(绕过 Spring Data 抽象)。 | QueryResponse response = solrTemplate.getSolrClient().query("mycore", solrQuery); | 灵活性高,但丧失类型安全。 |
| 提交控制 | solrTemplate.softCommit(); / solrTemplate.commit(); | 控制索引提交时机。 | — | save() 后默认不提交,需显式调用。 |
第十章:实战项目示例
10.1 电商商品搜索系统设计
| 设计要素 | 实现方式与配置 | 用途说明 | 示例配置 / 代码片段 | 注意事项 |
|---|---|---|---|---|
| Schema 设计 | 定义字段:id, title, description, price_f, category_s, brand_s, in_stock_b, popularity_i | 支持商品核心属性的搜索、过滤、排序。 | <field name="title" type="text_general" indexed="true" stored="true"/> <field name="price_f" type="pfloat" docValues="true"/> <field name="category_s" type="string" docValues="true"/> | 数值/布尔字段启用 docValues 以支持分面和排序。 |
| 多字段搜索 | 使用 eDisMax 查询解析器 + qf/pf 参数 | 用户输入”手机 高清”可匹配标题、描述等多字段。 | qf=title^3 description^1 brand^2 pf=title^5 | 权重(^)需根据业务重要性调整。 |
| 分面导航 | facet=true&facet.field=category_s&facet.field=brand_s&facet.range=price_f | 前端展示分类、品牌、价格区间筛选面板。 | f.price_f.facet.range.start=0&f.price_f.facet.range.end=10000&f.price_f.facet.range.gap=500 | 价格分面 gap 应根据商品分布动态调整。 |
| 排序策略 | sort=popularity_i desc, score desc | 默认按人气降序;支持按价格、上新时间排序。 | sort=price_f asc | 所有排序字段必须 docValues="true"。 |
| 高亮显示 | hl=true&hl.fl=title,description&hl.simple.pre=<em>&hl.simple.post=</em> | 在搜索结果中标出匹配关键词。 | — | 前端需信任并渲染 HTML 标签(注意 XSS 防护)。 |
| 自动建议 | Suggester 基于 title + brand 构建 | 输入”iph”时提示”iPhone 15”、“iPhone SE”等。 | lookupImpl=AnalyzingInfixLookupFactory field=suggest_field | suggest_field 可由 copyField 合并 title 和 brand。 |
| 性能保障 | FilterCache 缓存 category/brand/in_stock 过滤 | 高频筛选操作响应快。 | filterCache size=2048 | 避免对高基数字段(如 SKU)做分面。 |
10.2 日志全文检索平台搭建
| 组件/配置 | 实现方式 | 用途说明 | 示例配置 / 工具链 | 注意事项 |
|---|---|---|---|---|
| 数据接入 | Filebeat / Logstash → Kafka → 自定义消费者 → Solr | 实时采集日志并写入 Solr。 | Logstash output 插件:solr_http { host => "solr:8983" collection => "logs" } | 避免直接写入 Solr(易压垮),建议经消息队列缓冲。 |
| Schema 设计 | 字段:log_id, message_txt, level_s, service_s, host_s, timestamp_tdt | 支持按服务、级别、主机、时间范围查询。 | message_txt 使用 text_general 分词;timestamp_tdt 类型为 pdate | timestamp 必须为 ISO8601 格式(如 2025-01-01T12:00:00Z)。 |
| 时间范围查询 | q=timestamp_tdt:[NOW-7DAYS TO NOW] | 快速检索最近 N 天日志。 | — | pdate 字段支持 NOW、HOUR、DAY 等相对时间语法。 |
| 关键词高亮 | hl.fl=message_txt | 在日志内容中高亮错误关键词(如”ERROR”、“timeout”)。 | — | 高亮对大文本性能影响小,因只返回片段。 |
| 滚动索引策略 | 按天创建 Collection(logs-2025-02-01, logs-2025-02-02…) | 避免单索引过大;便于冷热分离和删除旧数据。 | 脚本每日创建新 Collection 并更新别名 | 使用 Solr Aliases 统一查询入口(如 logs-current)。 |
| 冷数据归档 | 将旧 Collection 移至低配节点或转存 HDFS | 降低成本,保留历史日志。 | — | Solr 不直接支持 HDFS,需结合外部工具(如 DistCp)。 |
| 查询限流 | 在 reverse proxy(如 Nginx)层限制 QPS | 防止异常查询拖垮集群。 | nginx limit_req_zone | Solr 本身无内置限流机制。 |
10.3 多语言文档搜索支持
| 功能 | 实现方式 | 用途说明 | 示例配置 | 注意事项 |
|---|---|---|---|---|
| 多语言分词 | 为每种语言定义独立 fieldType(text_en, text_zh, text_ja) | 确保不同语言使用对应分词器。 | <fieldType name="text_en" class="solr.TextField"><analyzer><tokenizer class="solr.StandardTokenizerFactory"/><filter class="solr.EnglishPossessiveFilterFactory"/><filter class="solr.LowerCaseFilterFactory"/></analyzer></fieldType> | 中文推荐 smartcn 或集成 ik-analyzer;日文用 Kuromoji。 |
| 语言检测 | 客户端预处理(如 Apache Tika)或 Solr Update Processor | 自动识别文档语言并路由到对应字段。 | 在 solrconfig.xml 中配置 LangDetectLanguageIdentifierUpdateProcessor | 语言检测有误判可能,关键场景建议客户端指定。 |
| 多语言字段设计 | copyField 将 content 复制到 content_en, content_zh 等 | 同一文档支持多语言检索。 | <copyField source="content" dest="content_zh"/> <copyField source="content" dest="content_en"/> | 存储开销大,仅对高频语言启用。 |
| 查询时指定语言 | q={!lucene}content_zh:人工智能 | 用户选择语言后,查询对应字段。 | 前端下拉框选择语言 → 构造 q=content_{lang}:keyword | 需确保前端与后端语言代码一致(如 zh/en/ja)。 |
| 同义词与停用词 | 每种语言配置独立的 synonyms.txt 和 stopwords.txt | 提升相关性(如英文”car” ≈ “automobile”)。 | 在 fieldType 的 analyzer 中引用 <filter class="solr.SynonymGraphFilterFactory" synonyms="synonyms_en.txt"/> | 同义词文件需定期维护。 |
| 拼写检查多语言 | 为每种语言配置独立 SpellChecker | 提供语言相关的拼写建议。 | spellcheck.dictionary=en_dict(基于 content_en 字段) | 需分别构建各语言字典。 |
10.4 安全认证与权限控制(Basic Auth / Kerberos)
| 安全机制 | 配置方式 | 用途说明 | 示例配置 / 命令 | 注意事项 |
|---|---|---|---|---|
| Basic Auth(基础认证) | 在 security.json 中定义用户和角色 | 限制 Solr Admin UI 和 API 访问。 | {"authentication":{"blockUnknown":true,"class":"solr.BasicAuthPlugin","credentials":{"admin":"...hash..."}}} | 密码需用 solr.in.sh hash 生成;仅适用于测试或内网。 |
| 启用 security.json | 将 security.json 上传至 ZK:zkcli.sh -zkhost zk:2181 -cmd putfile /security.json security.json | 使安全配置生效(SolrCloud 模式)。 | — | 单机模式将 security.json 放在 $SOLR_HOME。 |
| 角色与权限映射 | 定义 permissions(如 read, update, admin)并绑定角色 | 细粒度控制 Collection 操作权限。 | "authorization":{"class":"solr.RuleBasedAuthorizationPlugin","permissions":[{"name":"read","role":"reader"},{"name":"update","role":"writer"}]} | 权限包括:security-edit, core-admin-read, collection-admin-edit 等。 |
| 客户端认证 | 请求时携带 Authorization 头 | 应用程序访问受保护 Solr。 | curl -u admin:password "http://solr:8983/solr/mycore/select?q=*:*" | Spring Boot 中可通过 SolrClient 设置 credentialsProvider。 |
| Kerberos 集成 | 配置 JAAS 文件 + Solr 启动参数 + security.json | 企业级单点登录(SSO),与 Active Directory 集成。 | -Djava.security.auth.login.config=jaas.conf -Dsun.security.krb5.debug=true | 配置复杂,需 KDC 服务器;适用于 Hadoop 生态环境。 |
| TLS/SSL 加密 | 配置 Solr 使用 HTTPS(Jetty 或反向代理) | 加密传输,防止窃听。 | 在 solr.in.sh 中设置 SOLR_SSL_KEY_STORE、SOLR_SSL_TRUST_STORE | Basic Auth 必须配合 HTTPS,否则密码明文传输。 |
| 审计日志 | 启用 RequestLoggingFilter 记录所有请求 | 追踪谁在何时执行了什么操作。 | 在 webdefault.xml 中配置 org.eclipse.jetty.server.RequestLog | 日志量大,需定期归档。 |