关于 frappe-core-search
面向 Frappe 开发者的搜索技能,涵盖链接字段、全局、网站全文和 SQLite 搜索,介绍各子系统的选择、配置与定制方法。
主要功能
- 01配置链接字段自动补全
- 02定制链接字段查询
- 03设置全局搜索索引
- 04SQLiteSearch 评分与拼写纠正
- 05选择合适的搜索子系统
适用场景
- 01按易读字段搜索 DocType 记录
- 02用筛选条件定制链接字段结果
- 03设置跨 DocType 搜索
- 04为项目数据构建 SQLiteSearch 索引
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ impertio-studio/ frappe_claude_skill_package --skill frappe-core-search安装后在 Claude Code 中输入/frappe-core-search确认已加载。
附带文件references/global-website-search.mdreferences/link-search-api.md
详细介绍
Frappe 搜索系统
四种搜索子系统
| 子系统 | 模块 | 用途 | 实时? |
|---|---|---|---|
| 链接字段搜索 | frappe.desk.search | 链接字段中的自动补全 | 是 |
| 全局搜索 | frappe.utils.global_search | 跨 DocType 搜索(桌面端 + 网站) | 否(每 15 分钟同步) |
| FullTextSearch | frappe.search.full_text_search | 基于 Whoosh 的索引(网站) | 重建时 |
| SQLiteSearch [v15+] | frappe.search.sqlite_search | 带评分和拼写纠正的 FTS5 | 是(每 5 分钟处理队列) |
决策树
What search do you need?
│
├─ Link field autocomplete (user types in a Link field)?
│ ├─ Default behavior sufficient → Configure search_fields on DocType
│ └─ Custom logic needed → standard_queries hook or query parameter
│
├─ Cross-doctype search (user searches for anything)?
│ ├─ Desk users → Global Search (auto-enabled)
│ │ └─ Set in_global_search=1 on important fields
│ └─ Website visitors → web_search() or WebsiteSearch (Whoosh)
│
├─ Custom full-text search for your app [v15+]?
│ └─ SQLiteSearch subclass + sqlite_search hook
│ → Spelling correction, recency boost, custom scoring
│
└─ Awesomebar customization?
└─ Client-side: override build_options or use search dialog
链接字段搜索
配置 search_fields(最常见需求)
# In DocType JSON or via customize form
{
"search_fields": "customer_name, customer_group",
"title_field": "customer_name",
"show_title_field_in_link": 1
}
务必设置 search_fields —— 否则,用户只能按 name 搜索(通常是 CUST-001 这样的代码)。
链接搜索的工作方式
- 用户在链接字段中输入内容 → 调用
search_link(doctype, txt) - 搜索范围:
name+title_field+search_fields - 允许的字段类型:Data、Text、Small Text、Long Text、Link、Select、Autocomplete、Read Only、Text Editor
- 前缀匹配的排名高于子串匹配
- 自动遵循
enabled/disabled字段
自定义链接查询
# hooks.py — override search for a specific DocType
standard_queries = {
"Customer": "my_app.queries.customer_query"
}
# my_app/queries.py — MUST be @frappe.whitelist()
@frappe.whitelist()
def customer_query(doctype, txt, searchfield, start, page_length, filters,
as_dict=False, reference_doctype=None,
ignore_user_permissions=False):
# Return list of dicts: [{"value": name, "description": label}, ...]
return frappe.db.sql("""
SELECT name, customer_name as description
FROM `tabCustomer`
WHERE (name LIKE %(txt)s OR customer_name LIKE %(txt)s)
AND status = 'Active'
ORDER BY customer_name
LIMIT %(start)s, %(page_length)s
""", {"txt": f"%{txt}%", "start": start, "page_length": page_length},
as_dict=True)
按字段覆盖查询
// In Client Script or Form JS
frappe.ui.form.on("Sales Order", {
setup(frm) {
frm.set_query("customer", () => ({
filters: { status: "Active", territory: frm.doc.territory }
}));
}
});
全局搜索
启用
在应支持搜索的 DocType 字段上设置 in_global_search = 1。
工作方式
- 已索引字段存储在
__global_search表中 - 每 15 分钟通过 Redis 队列同步
- 使用数据库原生全文搜索:MariaDB
MATCH...AGAINST、PostgreSQLTSVECTOR - 结果按权限过滤
重建索引
# Rebuild for specific DocType
from frappe.utils.global_search import rebuild_for_doctype
rebuild_for_doctype("Sales Order")
# Rebuild everything
from frappe.utils.global_search import rebuild
rebuild()
hooks.py 配置
# Default doctypes for global search
global_search_doctypes = {
"Default": [
{"doctype": "Contact"},
{"doctype": "Customer"},
{"doctype": "Sales Order"},
]
}
SQLiteSearch [v15+]
创建自定义搜索
# my_app/search.py
from frappe.search.sqlite_search import SQLiteSearch
class ProjectSearch(SQLiteSearch):
INDEX_SCHEMA = {
"metadata_fields": ["project", "owner", "status"],
"tokenizer": "unicode61 remove_diacritics 2 tokenchars '-_'",
}
INDEXABLE_DOCTYPES = {
"Task": {
"fields": ["name", {"title": "subject"}, {"content": "description"},
"modified", "project"],
"filters": {"status": ("!=", "Cancelled")}
},
"Project": {
"fields": ["name", {"title": "project_name"}, {"content": "notes"},
"modified", "status"],
}
}
def get_search_filters(self, query, scope=None):
"""Permission filtering — return additional WHERE conditions"""
return {}
在 hooks.py 中注册
sqlite_search = ['my_app.search.ProjectSearch']
功能(自动)
- 拼写纠正:基于三元组的模糊匹配
- 近期内容加权:1.8x(24 小时)→ 1.5x(7 天)→ 1.2x(30 天)→ 1.1x(90 天)
- 可恢复索引:跟踪进度,原子替换
- 自动调度:每 3 小时构建索引,每 5 分钟处理队列,文档事件会触发更新
反模式
| 切勿 | 务必 | 原因 |
|---|---|---|
在 DocType 中省略 search_fields | 设置 search_fields 以使用方便用户识别的名称 | 用户无法通过名称代码找到记录 |
自定义查询未使用 @frappe.whitelist() | 添加 @frappe.whitelist() 装饰器 | 会静默失败——被安全检查拒绝 |
| 在搜索中使用不带参数的原始 SQL | 使用参数化查询(%(txt)s) | 存在 SQL 注入风险 |
| 在全局搜索中索引所有字段 | 仅在关键字段上设置 in_global_search=1 | 表会膨胀,拖慢每 15 分钟一次的同步 |
| 将全局搜索用于实时搜索 | 实时搜索使用链接字段搜索 | 全局搜索有 15 分钟的同步延迟 |
在 SQLiteSearch 中跳过 get_search_filters() | 实现权限过滤 | 会返回所有结果,不考虑访问权限 |
| 索引已取消/已删除的文档 | 在 INDEXABLE_DOCTYPES 中设置 filters | 过时结果会使用户困惑 |
版本差异
| 功能 | v14 | v15+ |
|---|---|---|
| 链接搜索缓存 | -- | @http_cache(max_age=60) |
link_fieldname 参数 | -- | 已添加 |
page_length 默认值 | 20 | 10 |
| SQLiteSearch(FTS5) | -- | 完整实现 |
| 拼写纠正 | -- | 基于三元组 |
| 近期内容加权 | -- | 基于时间的倍率 |
sqlite_search hook | -- | 可用 |
| 全局搜索 | 是 | 是 |
| Whoosh FullTextSearch | 是 | 是(旧版) |
参考文件
评论
支持 Markdown