mcpField
F
frappe-core-search

frappe-core-search

github.com/impertio-studio开发198112 次安装30 周前更新
代码仓库

关于 frappe-core-search

面向 Frappe 开发者的搜索技能,涵盖链接字段、全局、网站全文和 SQLite 搜索,介绍各子系统的选择、配置与定制方法。

主要功能

  1. 01配置链接字段自动补全
  2. 02定制链接字段查询
  3. 03设置全局搜索索引
  4. 04SQLiteSearch 评分与拼写纠正
  5. 05选择合适的搜索子系统

适用场景

  1. 01按易读字段搜索 DocType 记录
  2. 02用筛选条件定制链接字段结果
  3. 03设置跨 DocType 搜索
  4. 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 分钟同步)
FullTextSearchfrappe.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 这样的代码)。

链接搜索的工作方式
  1. 用户在链接字段中输入内容 → 调用 search_link(doctype, txt)
  2. 搜索范围:name + title_field + search_fields
  3. 允许的字段类型:Data、Text、Small Text、Long Text、Link、Select、Autocomplete、Read Only、Text Editor
  4. 前缀匹配的排名高于子串匹配
  5. 自动遵循 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、PostgreSQL TSVECTOR
  • 结果按权限过滤
重建索引
# 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过时结果会使用户困惑

版本差异

功能v14v15+
链接搜索缓存--@http_cache(max_age=60)
link_fieldname 参数--已添加
page_length 默认值2010
SQLiteSearch(FTS5)--完整实现
拼写纠正--基于三元组
近期内容加权--基于时间的倍率
sqlite_search hook--可用
全局搜索是是
Whoosh FullTextSearch是是(旧版)

参考文件

评论

支持 Markdown