Fess 15.9.0 查询语言详解
系统梳理 Fess 15.9.0 的检索查询语言——布尔组合、字段限定、范围、通配符、模糊、短语与邻近、加权、排序、分面与隐藏条件 ex_q,每条语法均在真实运行的 Fess 15.9.0 实例上逐条执行并照抄响应回显;同时用实测数据澄清三类高频陷阱:中文二元分词对短语检索的影响、Keyword 类字段的全值精确匹配语义、特殊字符转义规则。
Fess 15.9.0 查询语言详解
目标:系统梳理 Fess 15.9.0 的检索查询语言——布尔组合、字段限定、范围、通配符、模糊、短语与邻近、加权、排序、分面与隐藏条件 ex_q,每条语法均在真实运行的 Fess 15.9.0 实例上逐条执行并照抄响应回显;同时用实测数据澄清三类高频陷阱:中文二元分词对短语检索的影响、Keyword 类字段的全值精确匹配语义、特殊字符转义规则。
一、环境信息
本篇实测基于以下环境,全文回显均出自该实例:
| 项目 | 内容 |
|---|---|
| Fess 版本 | 15.9.0(官方 2026-10-15 发布的最新稳定版) |
| 检索引擎 | OpenSearch 3.9.0(Fess 官方定制版,独立部署,与 Fess 通过 9200 端口互联) |
| 操作系统 | Linux x86_64(JDK 21 运行时) |
| 检索服务端口 | 8080(Fess Web 与 JSON API 共用) |
| 管理账号 | admin(首次登录已按提示完成密码初始化) |
| 测试语料 | 内网测试站 http://crawl-target:8001/,共 6 个 HTML 页面,已全部爬取入库 |
测试语料的 6 个页面及其索引内字段值(后续用例的命中结果都以此为基础,读者可用同结构语料复现):
| 标题 | URL 路径 | content_length | filetype | lang |
|---|---|---|---|---|
| 企业搜索引擎知识库 - 首页 | / | 876 | html | zh-cn |
| 网络爬虫抓取优化技巧 | /crawler-tips.html | 870 | html | zh-cn |
| Fess 全文搜索服务器介绍 | /fess-intro.html | 1015 | html | zh-cn |
| Elasticsearch 与企业搜索选型对比 | /es-compare.html | 900 | html | zh-cn |
| 全文搜索查询语法入门 | /search-syntax.html | 951 | html | zh-cn |
| OpenSearch 搜索集群部署指南 | /opensearch-cluster.html | 887 | html | zh-cn |
6 个页面的 last_modified 与 timestamp 均为 2026-10-23T19:46:33.000Z。部署这套环境(含语料爬取与访问令牌创建)的完整过程见 《Fess 15.9.0 Docker Compose 部署指南》,组件选型背景见 《Fess 15.9.0 介绍与选型指南》。
二、前置条件
- Fess 服务已运行且完成基础爬取:搜索接口能返回语料命中。
- 已创建一个具备检索权限的访问令牌(管理界面登录后进入「系统 → 访问令牌」创建;令牌的权限位决定按角色过滤的范围,建议至少包含 guest 角色权限
Rguest,否则令牌检索会过滤掉仅对访客开放的角色文档——实测中令牌缺Rguest时q=fess返回record_count=0,补齐权限位后同一查询返回 3 条)。 - 本篇统一以 REST JSON API 作为实测入口(便于照抄回显),检索语法与搜索框完全同源:
curl -s 'http://<Fess服务器>:8080/api/v2/search?q=<查询串>' \
-H 'Authorization: Bearer <访问令牌>'
回显结构固定为 response 对象,其中 q 为查询原文回显、record_count 为命中总数、data 为结果数组、exec_time/query_time 为耗时。带 fields 参数可精简响应字段(如 fields=score,title 只返回得分与标题)。
三、查询语言总览
Fess 的查询语言是一套构建在 Apache Lucene 查询语法之上的检索 DSL,按作用位置分三层:
| 层 | 入口 | 说明 |
|---|---|---|
| 查询串语法 | 搜索界面搜索框、q 参数 | 本篇主体:布尔、字段限定、范围、通配、模糊、短语、邻近、加权、排序算子全部写在 q 里 |
| API 检索参数 | /api/v2/search 查询参数 | num(页大小)、start(偏移)、sort(排序)、fields(响应字段)、facet.field/facet.size(分面)、label(标签过滤参数) |
| 隐藏条件 | ex_q 参数 | 不显示在搜索框、服务端强制 AND 追加的条件,适合在结果页链接中固化过滤 |
与 CLI 的分工:Fess 没有独立的命令行检索工具,检索入口只有搜索界面与 HTTP API 两条路;运维侧的系统管理走管理界面与 Admin API(三者的边界见 《Fess 15.9.0 介绍与选型指南》第 5 章)。
语法能力速览(每项的实测回显见对应章节):
| 能力 | 算子/写法 | 章节 |
|---|---|---|
| 布尔组合 | AND OR NOT(大写)、空格默认 AND、+ - 简写、() 分组 | 5.1 |
| 字段限定 | title:词、url:值 等 18 个字段 | 5.2 |
| 范围 | content_length:[1000 TO 10000]、[ ] 闭 { } 开、* 开界 | 5.3 |
| 通配符 | ? 单字符、* 多字符 | 5.4 |
| 模糊 | 词~N(Damerau-Levenshtein 编辑距离) | 5.5 |
| 短语/邻近 | "词1 词2"、"词1 词2"~N | 5.6 |
| 加权 | 词^100(整数或小数) | 5.7 |
| 排序 | sort:字段[.asc/.desc](q 内嵌)或 sort 参数 | 5.8 |
四、语法基础
4.1 字段与数据类型
官方公布的默认可检索字段(默认权限下全部可用,无需额外配置):
| 字段 | 含义 | 检索类型 |
|---|---|---|
| url | 爬取的完整 URL | Keyword |
| host | URL 中的主机名(实测含端口,如 crawl-target:8001) | Keyword |
| site | 去掉协议与查询串后的主机名+路径,按前缀匹配 | Keyword |
| title | 标题 | Text |
| content | 正文 | Text |
| content_length | 文档大小(字节) | Numeric |
| last_modified | 文档最后修改时间 | Date |
| timestamp | 入库时间(取不到修改时间时等于爬取时间) | Date |
| mimetype | MIME 类型(如 text/html) | Keyword |
| filetype | 由 MIME 推定的文件类型(如 html、pdf) | Keyword |
| filename | URL 路径末端的文件名 | Keyword |
| label | 文档被赋予的标签值 | Keyword |
| lang | 语言代码(如 zh-cn) | Keyword |
| anchor | 页面内提取的链接目标(Web 爬取才有) | Keyword |
| click_count | 点击次数 | Numeric |
| favorite_count | 收藏次数 | Numeric |
| owner / last_modifier | 文件属主 / 修改者(文件爬取才有) | Keyword |
四类检索类型的行为差异直接决定写法:
- Text(title/content):全文按分词词元匹配,支持短语、邻近、通配、模糊;
- Keyword(url/host/mimetype/lang 等):对整个值做精确匹配,天然支持通配符/前缀写法来近似子串匹配;
- Numeric(content_length 等):支持范围
[A TO B]; - Date(last_modified/timestamp):支持
2026-10-23、2026-10-23T10:45:23Z、毫秒级三种粒度与now相对运算。
4.2 分词机制实测
查询行为差异的根源在分词。直接对语料库 content 字段调用 OpenSearch _analyze 接口,得到 Fess 实际的切分结果:
POST /fess.search/_analyze
{"field":"content","text":"全文搜索集群部署与爬虫抓取"}
实测回显:
tokens: ['全文', '文捜', '捜索', '索集', '集群', '群部', '部署', '署与', '与爬', '爬虫', '虫抓', '抓取']
两个关键结论:
- 中文按二字滑动切分(bigram):
全文搜索切成全文、文捜、捜索三个词元,相邻词元共享一个汉字。这解释了 5.6 节的短语陷阱:"全文 搜索"在词元流中隔着文捜,短语匹配失败(实测record_count=0),而不加引号的 AND 检索命中 3 条。 - 英文按空白/标点切词后做词干归一:
Fess supports Chinese full-text search切分为['fess', 'support', 'chines', 'full', 'text', 'search']——supports归一为support,chinese归一为chines,因此单复数、动词变位不区分,检索ROBOTS与robots等效(5.1 节实测)。
4.3 大小写归一
词元统一小写归一,实测同一词三种写法命中完全一致:
| 查询串 | record_count | 命中 |
|---|---|---|
robots | 1 | 网络爬虫抓取优化技巧 |
ROBOTS | 1 | 网络爬虫抓取优化技巧 |
ocr | 2 | 网络爬虫抓取优化技巧;Fess 全文搜索服务器介绍 |
注意:布尔算子是唯一例外——OR/AND/NOT 必须大写,小写会被当作普通词(5.1 节 T07 实测)。
4.4 特殊字符与转义
以下字符在查询语法中有专用语义,按字面检索时必须用 \ 转义:
+ - && || ! ( ) { } [ ] ^ " ~ * ? : \ /
对照实测:mimetype 的值是 text/html,斜杠不转义时返回 0 条,转义后 6 条全中:
| 查询串 | record_count |
|---|---|
mimetype:text/html | 0 |
mimetype:text\/html | 6 |
连字符 - 在字段限定词内部则不需要转义:lang:zh-cn 与 lang:zh\-cn 实测均命中 6 条,且单独检索 lang:zh 为 0 条——说明 zh-cn 被整体当作一个词元处理。但 - 出现在词的开头就是排除算子(搜索 -Elasticsearch,见 5.1 节),因此对含连字符的值保持转义习惯最稳妥。
五、核心语法分类详解
以下每条查询均在实例上执行,回显的 record_count 与命中标题逐条照抄。
5.1 布尔与分组
空格分隔默认 AND,显式 AND 等效(必须大写、两侧留空格):
| 查询串 | record_count | 命中标题 |
|---|---|---|
搜索 服务器 | 2 | 企业搜索引擎知识库 - 首页;Fess 全文搜索服务器介绍 |
搜索 AND 服务器 | 2 | 企业搜索引擎知识库 - 首页;Fess 全文搜索服务器介绍 |
搜索 AND 集群 | 2 | 企业搜索引擎知识库 - 首页;OpenSearch 搜索集群部署指南 |
OR 取并集;NOT 排除;小写 or 不是算子,被当作普通词参与 AND 后导致 0 命中:
| 查询串 | record_count | 命中标题 |
|---|---|---|
搜索 OR 集群 | 5 | 企业搜索引擎知识库 - 首页;OpenSearch 搜索集群部署指南;Fess 全文搜索服务器介绍;Elasticsearch 与企业搜索选型对比;全文搜索查询语法入门 |
搜索 NOT Elasticsearch | 2 | Fess 全文搜索服务器介绍;全文搜索查询语法入门 |
搜索 or 集群 | 0 | (小写 or 被当作普通词,AND 语义下无文档同时含三词) |
简写形式:-词 等效 NOT 词,+词 表示必须包含;() 改变结合优先级:
| 查询串 | record_count | 命中标题 |
|---|---|---|
搜索 -Elasticsearch | 2 | Fess 全文搜索服务器介绍;全文搜索查询语法入门 |
(搜索 OR 集群) NOT Elasticsearch | 2 | Fess 全文搜索服务器介绍;全文搜索查询语法入门 |
+Fess +爬虫 | 3 | Fess 全文搜索服务器介绍;Elasticsearch 与企业搜索选型对比;企业搜索引擎知识库 - 首页 |
布尔与字段限定可以自由组合(AND/OR 连接字段子句):
| 查询串 | record_count | 命中标题 |
|---|---|---|
title:集群 OR content:爬虫 | 5 | Elasticsearch 与企业搜索选型对比;Fess 全文搜索服务器介绍;网络爬虫抓取优化技巧;OpenSearch 搜索集群部署指南;企业搜索引擎知识库 - 首页 |
title:集群 AND content:爬虫 | 0 | (标题含集群的页面正文无爬虫词) |
(title:集群 OR title:爬虫) NOT Elasticsearch | 1 | 网络爬虫抓取优化技巧 |
第三条是组合降噪的典型:标题含「集群」的《OpenSearch 2.x Docker Compose 部署指南》被 NOT Elasticsearch 排除,说明其正文含有 Elasticsearch 词元——分组把 OR 的作用域限制在两个字段子句内,再整体排除。
5.2 字段限定检索
语法为 字段:值。Text 类字段(title/content)按词元匹配,Keyword 类字段按全值精确匹配:
| 查询串 | record_count | 命中标题 |
|---|---|---|
title:爬虫 | 1 | 网络爬虫抓取优化技巧 |
title:集群 | 1 | OpenSearch 搜索集群部署指南 |
filename:search-syntax.html | 1 | 全文搜索查询语法入门 |
filetype:html | 6 | 全部 6 页 |
site:crawl-target | 6 | 全部 6 页(site 按前缀匹配) |
Keyword 全值语义的两个对照实测——子串直接写一律 0 命中,因为 url 的全值是 http://crawl-target:8001/crawler-tips.html、host 的全值是 crawl-target:8001:
| 查询串 | record_count | 结论 |
|---|---|---|
url:crawler-tips.html | 0 | 子串≠全值 |
host:crawl-target | 0 | host 实际含端口,子串≠全值 |
host:crawl-target* | 6 | 通配符补齐尾部即可命中 |
url:"http://crawl-target:8001/crawler-tips.html" | 1 | 引号包裹整值短语命中 |
url:http\:\/\/crawl-target\:8001\/crawler-tips.html | 1 | 全转义词元等效 |
url:crawl-target\:8001\/crawler-tips.html | 0 | 缺协议前缀,仍不是全值 |
经验法则:Keyword 字段要么写完整值(含协议、端口),要么用 * / 引号短语;site: 是唯一按前缀匹配的关键字字段,适合站点圈定。
5.3 范围检索
语法 字段:[下界 TO 上界],方括号闭区间、花括号开区间,单边 * 表示开界。实测语料的 content_length 在 870-1015 之间:
| 查询串 | record_count | 命中标题 |
|---|---|---|
content_length:[1000 TO 10000] | 1 | Fess 全文搜索服务器介绍(1015) |
content_length:[870 TO 900] | 4 | 企业搜索引擎知识库 - 首页;网络爬虫抓取优化技巧;Elasticsearch 与企业搜索选型对比;OpenSearch 搜索集群部署指南 |
content_length:{870 TO 900] | 3 | 企业搜索引擎知识库 - 首页;Elasticsearch 与企业搜索选型对比;OpenSearch 搜索集群部署指南 |
content_length:[5000 TO *] | 0 | (开上界,语料最大 1015) |
{870 TO 900] 比 [870 TO 900] 恰好少掉 content_length=870 的《网络爬虫抓取优化技巧》,验证了下界独占语义。日期范围用 ISO 日期(2026-10-23)或完整时间戳(2026-10-23T19:46:33Z):
| 查询串 | record_count |
|---|---|
last_modified:[2026-10-23 TO 2026-10-24] | 6 |
日期还支持 now 相对运算(now-1d、now/M 舍入等),适合「最近一天」「本月内」类需求;范围子句可与普通词直接组合,实测 爬虫 last_modified:[2026-10-23 TO 2026-10-24] 返回 4 条(正文含爬虫的 4 页,全部落在时间窗内)。
5.4 通配符检索
? 匹配单个字符、* 匹配零或多个字符,可出现在词首、词中、词尾,也可与字段限定叠加:
| 查询串 | record_count | 命中标题 |
|---|---|---|
opensea* | 4 | OpenSearch 搜索集群部署指南;Elasticsearch 与企业搜索选型对比;企业搜索引擎知识库 - 首页;Fess 全文搜索服务器介绍 |
elastic* | 3 | Elasticsearch 与企业搜索选型对比;企业搜索引擎知识库 - 首页;OpenSearch 搜索集群部署指南 |
爬? | 4 | 网络爬虫抓取优化技巧;企业搜索引擎知识库 - 首页;Fess 全文搜索服务器介绍;Elasticsearch 与企业搜索选型对比 |
title:Open* | 1 | OpenSearch 搜索集群部署指南 |
爬? 命中 4 条说明通配符作用于索引词元(二元分词后的 爬虫 词元被 爬? 覆盖),对中文同样可用。注意官方文档明确:通配符作用于词,短语查询不支持通配符。
5.5 模糊检索
词~N 按 Damerau-Levenshtein 编辑距离(相邻字符换位记 1)容错匹配,词~ 为自动距离:
| 查询串 | record_count | 命中标题 |
|---|---|---|
ferss~1 | 3 | Fess 全文搜索服务器介绍;企业搜索引擎知识库 - 首页;Elasticsearch 与企业搜索选型对比 |
ferzz~1 | 0 | (编辑距离 2,超出 ~1 容差) |
opensearsh~1 | 4 | OpenSearch 搜索集群部署指南;Elasticsearch 与企业搜索选型对比;企业搜索引擎知识库 - 首页;Fess 全文搜索服务器介绍 |
fess~ | 3 | Fess 全文搜索服务器介绍;Elasticsearch 与企业搜索选型对比;企业搜索引擎知识库 - 首页 |
两条对照精准验证了距离语义:ferss 距 fess 为 1(替换 r→s),命中;ferzz 距离为 2,0 命中;opensearsh 距 opensearch 仅为相邻字符 sh→hs 的一次换位,Damerau 计 1,~1 即命中 4 条。
5.6 短语与邻近检索
双引号短语要求词元按序相邻;加 ~N 放宽为词元间隔不超过 N 个位置。中文短语受二元分词影响最直接:
| 查询串 | record_count | 命中标题 |
|---|---|---|
"搜索 集群" | 0 | (搜索与集群词元间隔着索集,不相邻) |
"全文 搜索" | 0 | (同上,隔着文捜) |
全文 搜索 | 3 | 全文搜索查询语法入门;企业搜索引擎知识库 - 首页;Fess 全文搜索服务器介绍 |
"OpenSearch 搜索" | 3 | OpenSearch 搜索集群部署指南;企业搜索引擎知识库 - 首页;Fess 全文搜索服务器介绍 |
title:"Fess 全文搜索服务器介绍" | 1 | Fess 全文搜索服务器介绍 |
"集群 爬虫" | 0 | (两词相距远) |
"集群 爬虫"~12 | 1 | 企业搜索引擎知识库 - 首页 |
"搜索 爬虫"~6 | 2 | 企业搜索引擎知识库 - 首页;Fess 全文搜索服务器介绍 |
结论与建议:
- 拉丁词与中文相邻(
"OpenSearch 搜索")、或完整标题引号检索(title:"Fess 全文搜索服务器介绍")能正常命中——因为查询串与索引文本走同一套切分,词元序列天然对齐; - 纯中文短语最容易踩「隔着共享字词元」的坑:想找「全文搜索」字样,短语
"全文 搜索"反而查不到,应直接用不加引号的全文 搜索(AND 语义)或放宽为邻近"全文 搜索"~3; - 邻近度 N 是位置上限,语料越短所需 N 越小;
"集群 爬虫"~12才命中首页,说明两词在首页词元流中相距 12 个位置以内。
5.7 加权检索
词^权重 提升指定词的打分权重(整数或小数;0<p<1 降权),词与 ^ 之间不留空格。用 fields=score,title 观察得分变化:
基线 q=Fess 爬虫:
Fess 全文搜索服务器介绍 score=0.09091364
Elasticsearch 与企业搜索选型对比 score=0.034168206
企业搜索引擎知识库 - 首页 score=0.030636644
加权 q=Fess^100 爬虫:
Fess 全文搜索服务器介绍 score=7.7533646
企业搜索引擎知识库 - 首页 score=2.2974153
Elasticsearch 与企业搜索选型对比 score=1.6643621
三条记录的 record_count 保持 3 不变,但分值整体放大且排序随权重变化——把 ^100 从 Fess 移到爬虫(Fess 爬虫^100)后,Elasticsearch 对比页从第三跃升第一(score=1.6643621),Fess 介绍页降到第二(score=1.2426001),首页垫底(score=0.6268774)。加权不改变召回集合,只改变相关度排序,适合把品牌词、核心词置顶的运营场景。
带权重的完整响应回显(节选):
{
"response": {
"status": 0,
"q": "Fess^100 爬虫",
"record_count": 3,
"search_query": "Fess^100 爬虫",
"data": [
{
"title": "Fess 全文搜索服务器介绍",
"content_title": "<strong>Fess</strong> 全文搜索服务器介绍",
"score": 7.7533646,
"content_length": "1015",
"url_link": "http://crawl-target:8001/fess-intro.html"
}
……(以下两条记录与统计字段省略)
]
}
}
5.8 排序检索
两种写法等效:q 内嵌 sort:字段,或独立 sort 参数;后缀 .asc/.desc,省略默认升序。默认可排序字段:created、content_length、last_modified、filename、score、timestamp、click_count、favorite_count。
| 查询串 | record_count | 排序结果(按序) |
|---|---|---|
搜索 + sort=content_length | 5 | 首页(876) → OpenSearch 指南(887) → ES 对比(900) → 语法入门(951) → Fess 介绍(1015) |
搜索 + sort=content_length.desc | 5 | Fess 介绍(1015) → 语法入门(951) → ES 对比(900) → OpenSearch 指南(887) → 首页(876) |
搜索 sort:content_length | 5 | 与 sort 参数升序完全一致 |
搜索 + sort=score.desc | 5 | 首页 → Fess 介绍 → OpenSearch 指南 → ES 对比 → 语法入门 |
搜索 + sort=filename | 5 | es-compare → fess-intro → opensearch-cluster → search-syntax → 首页(首页 filename 为空排末位) |
q 内嵌写法与字段限定、排序后缀可叠加,实测 title:集群 sort:content_length.desc 正常返回 1 条《OpenSearch 2.x Docker Compose 部署指南》。多字段排序用逗号分隔(如 sort:content_length,score.desc)。
六、场景化查询模式
以下模板均经实测验证,可直接套用到生产检索入口(界面搜索框或 API q 参数)。
6.1 精确命中某个页面
Keyword 全值 + 引号(或全转义)是唯二可靠写法:
url:"http://crawl-target:8001/crawler-tips.html" → record_count=1
url:http\:\/\/crawl-target\:8001\/crawler-tips.html → record_count=1
6.2 字段圈定 + 排除降噪
(title:集群 OR title:爬虫) NOT Elasticsearch → record_count=1
搜索 -Elasticsearch → record_count=2
先用括号聚合字段子句,再用 NOT/- 剔除噪声词,比多个独立条件可读性更高。
6.3 时间窗 + 关键词组合
爬虫 last_modified:[2026-10-23 TO 2026-10-24] → record_count=4
搜索 sort=content_length.desc → record_count=5(按大小降序)
时间范围子句与普通词并排书写即为 AND 语义;再叠加 sort 参数即可做「最近变更优先」类列表。
6.4 分面钻取
facet.field 指定统计维度,facet.size 限制分组数,分面结果挂在响应的 facet_field 数组:
GET /api/v2/search?q=搜索&facet.field=filetype&facet.size=5&num=1
实测回显(节选):
"record_count": 5,
"facet_field": [
{
"name": "filetype",
"result": [
{ "value": "html", "count": 5 }
]
}
]
分面计数独立于结果页大小(num=1 只返回 1 条结果,分面仍统计全部 5 条命中),适合先看分布再钻取的交互。
6.5 隐藏条件 ex_q
ex_q 的语法与 q 完全一致(字段限定、短语、OR、范围均可用),服务端以 AND 并入主查询,且可传多个;空值与重复值被忽略:
| 查询串 | ex_q 参数 | record_count | 命中 |
|---|---|---|---|
搜索 | title:爬虫 | 0 | (搜索与爬虫标题无交集) |
搜索 | title:集群 | 1 | OpenSearch 搜索集群部署指南 |
典型用法是把过滤固化在结果页链接里:/search?q=keyword&ex_q=filetype:pdf,用户在搜索框只能看到 keyword,服务端强制追加文件类型过滤。
6.6 分页遍历
start(0 起始偏移)+ num(页大小)控制翻页,响应中的 start_record_number 是 1 起始展示值:
GET /api/v2/search?q=fess&start=1&num=2
实测回显(节选):
"record_count": 3,
"page_size": 2,
"page_number": 1,
"page_count": 2,
"start_record_number": 2,
"end_record_number": 3,
"page_numbers": ["1","2"]
七、运算符与参数速查
查询串运算符(均经 5.x 节实测):
| 运算符 | 写法 | 语义 |
|---|---|---|
| AND | 词1 AND 词2(可省略) | 同时包含 |
| OR | 词1 OR 词2 | 任一包含 |
| NOT | 词1 NOT 词2 | 排除 |
| + / - | +词 / -词 | 必须 / 排除 |
| 分组 | (表达式) | 优先级 |
| 字段限定 | 字段:值 | 圈定检索范围 |
| 范围 | 字段:[A TO B] / {A TO B] / [A TO *] | 闭 / 半开 / 开界区间 |
| 通配符 | ? / * | 单字符 / 多字符 |
| 模糊 | 词~N 或 词~ | 编辑距离容错 |
| 短语 | "词1 词2" | 词元相邻 |
| 邻近 | "词1 词2"~N | 间隔 ≤ N |
| 加权 | 词^N | 提权排序 |
| 排序 | sort:字段[.asc/.desc] | q 内嵌排序 |
API 检索参数(/api/v2/search,全部实测):
| 参数 | 示例 | 说明 |
|---|---|---|
| q | q=搜索 NOT Elasticsearch | 查询串(必填) |
| num | num=10 | 页大小,必须为正整数(传 0 报 num must be positive, got: 0) |
| start | start=1 | 结果偏移(0 起始) |
| sort | sort=content_length.desc | 与 q 内嵌 sort: 等效 |
| fields | fields=score,title,url | 精简响应字段 |
| facet.field / facet.size | facet.field=filetype&facet.size=5 | 分面维度与分组数 |
| label | label=manual | 标签过滤参数:未注册的标签名被忽略(实测照常返回 5 条);而 q 内写 label:manual 是字段精确匹配,未注册时返回 0 条——两种写法语义不同 |
| ex_q | ex_q=title:集群 | 隐藏条件,AND 并入,可多个 |
需转义的特殊字符:+ - && || ! ( ) { } [ ] ^ " ~ * ? : \ /
八、性能与陷阱(实测对照)
8.1 中文短语检索「看起来应该命中却为 0」
最高频的困惑。根因是 4.2 节的二元分词:中文按相邻两字滑动切词,短语要求词元相邻,于是 "全文 搜索" 在「全文搜索」文本中隔着词元 文捜 而失配。正确做法按需求选择:
- 只要两词都出现:去掉引号
全文 搜索(AND,实测 3 条); - 要求紧邻:对中文短语直接引号包裹原始连续文本
"OpenSearch 搜索"(拉丁词与中文分界处对齐,实测 3 条),或改用邻近"全文 搜索"~3。
8.2 Keyword 字段「子串查不到」
url:crawler-tips.html、host:crawl-target 均 0 命中(5.2 节实测)。Keyword 匹配的是整个值:host 含端口、url 含协议。解法三选一:写全值、通配符补齐(host:crawl-target*)、引号短语包全值。site: 是唯一前缀匹配的例外。
8.3 未转义特殊字符静默失配
mimetype:text/html 不报错但 0 命中(斜杠触发了正则/分隔语义),排查时容易误判成「没爬进来」。对照 mimetype:text\/html 命中 6 条。批量排查口诀:Keyword 字段查不到先转义 : / - 再试。
8.4 小写布尔词被当作普通词
搜索 or 集群 实测 0 条:小写 or 成为第三个 AND 条件。and/not 同理。运算符必须大写。
8.5 模糊与通配符的召回噪声
fess~ 与 ferss~1 都命中 3 条,但语料放大后模糊距离每 +1 召回近似词元数量指数级增长;* 词首通配符(官方允许 *test 写法)需要扫描整个词元字典,大索引下开销显著。生产建议:模糊距离 ≤2、通配符尽量挂在前缀侧(opensea* 优于 *search),并优先用字段限定收敛范围。
8.6 参数与令牌侧的边界行为
num=0:API 校验拒绝,返回{"status":1,"error":{"code":"invalid_request","message":"num must be positive, got: 0"}};- 令牌权限位缺
Rguest时,仅访客可见的角色文档被过滤(record_count=0),并非索引为空——排查检索为空先比对令牌权限与文档角色; !g等跳转触发词属于搜索界面行为,REST API 中按普通查询处理(实测!g fess照常返回 3 条站内结果,无跳转语义)。
九、常见问题
Q1:搜索框里写的语法和 API 里的一样吗?
一致。搜索框内容即 q 参数原文(响应中的 q/search_query 字段会回显查询原文,可用于核对转义是否生效)。差异在入口侧参数:搜索界面用 label 下拉与选项对话框传递排序/标签,API 用同名查询参数。
Q2:为什么 title:爬虫 能命中而 url:crawler-tips.html 不行?
title 是 Text 字段按词元匹配,url 是 Keyword 字段按全值精确匹配(详见 4.1 与 8.2)。
Q3:如何确认某条查询被如何解析了?
看响应中的 search_query(原文回显)与 highlight_params(高亮子句,如 &hq=Elasticsearch&hq=%E6%90%9C%E7%B4%A2,可看出 NOT 之外的词元如何参与高亮)。更底层可直接对 fess.search 索引调 _analyze 观察切分(4.2 节)。
Q4:字段名写错了会怎样? 不报错,按普通词处理,通常导致 0 命中或全库检索。字段名以 4.1 表为准。
Q5:中文检索还有什么可以调整的?
分词粒度与停用词属于配置层(fess_config.properties 的 query.* 键空间,逐键解析见 《Fess 15.9.0 配置参数详解》第五、六章);本篇只覆盖查询侧语法。
Q6:排序字段想用自定义字段怎么办?
在 fess_config.properties 的 query.additional.sort.fields 中以逗号追加字段名后即可参与排序(官方文档说明,默认为空)。
十、参考链接
- 官方 User Guide·Search 系列(AND/OR/NOT、Field、Sort、Wildcard、Range、Boost、Fuzzy、Proximity 等 13 页,本篇语法语义的权威来源):Fess 15.9 Documentation,https://fess.codelibs.org/stable/user/
- 官方 Search API 文档(
/api/v2/search参数与响应结构):https://fess.codelibs.org/stable/api/api-search.html - 官方 Special Characters(转义清单):https://fess.codelibs.org/stable/user/special-char.html
- 部署与初始化(含访问令牌创建、语料爬取实测):《Fess 15.9.0 Docker Compose 部署指南》
- 配置参数与分词相关配置项:《Fess 15.9.0 配置参数详解》
- 组件定位与同类选型:《Fess 15.9.0 介绍与选型指南》