mcpField
F
frappe-core-search

frappe-core-search

github.com/impertio-studio開発198112 回インストール30 週間前に更新
リポジトリ

frappe-core-search について

Frappe の開発者向けに、リンクフィールド、グローバル、Web 全文、SQLite の検索を扱うスキルです。各方式の選択、設定、カスタマイズを説明します。

主な機能

  1. 01リンクフィールドのオートコンプリート設定
  2. 02リンク検索クエリのカスタマイズ
  3. 03グローバル検索インデックスの設定
  4. 04SQLiteSearch のスコアリングとスペル修正
  5. 05検索サブシステムの選択指針

活用シーン

  1. 01DocType レコードを分かりやすいフィールドで検索
  2. 02フィルターでリンクフィールドの結果を調整
  3. 03DocType 横断検索の設定
  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 の検索システム

4 つの検索サブシステム

サブシステムモジュール用途リアルタイム?
リンクフィールド検索frappe.desk.searchリンクフィールドの自動補完はい
グローバル検索frappe.utils.global_searchDocType をまたいだ検索(デスクトップ+ウェブ)いいえ(15 分ごとに同期)
FullTextSearchfrappe.search.full_text_searchWhoosh ベースのインデックス(ウェブサイト)再構築時
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 テーブルに保存されます
  • Redis キューを介して 15 分ごとに同期されます
  • DB ネイティブの全文検索を使用します: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.8 倍(24 時間)→ 1.5 倍(7 日)→ 1.2 倍(30 日)→ 1.1 倍(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 フック--利用可能
グローバル検索はいはい
Whoosh FullTextSearchはいはい(レガシー)

参照ファイル

コメント