FTSearch / db.Search / DQL:Domino 三種搜尋機制怎麼選

FTSearch / db.Search / DQL:Domino 三種搜尋機制怎麼選

2026.05.29 約 1,717 字

Domino 14 之後、文件搜尋有三條技術路徑:FTSearch 走文字索引、db.Search@Formula 暴力掃描、DQL 走結構化 query 計畫。三條都能把符合條件的文件抓出來、但效能模型、index 成本、適合的資料規模差幾個數量級 — 選對的省下幾小時 batch / 幾百毫秒 request、選錯的就算把 formula 寫到最簡 也救不回來。

哪一條適合手上的問題?「庫多大」「條件偏文字還是結構化」「查詢頻率」這三個問題的答案組合決定路徑。

這篇是搜尋三部曲的 capstone — 多維度對比表、決策樹、Domino 14 把 FTSearch 整合進 DQL 的 @FTSearch() term、跟三個實戰場景(ad-hoc 查詢 / scheduled agent / 高頻 REST API)對應的建議路徑。


重點摘要

  • Domino 14 之後有三條搜尋路徑FTSearch(FT index)、db.Search(@Formula 全掃)、DQL(catalog + NIF + bulk readers)
  • 三者本質差異:FTSearch 走文字索引(適合「找含某字的」)、db.Search 走逐文 evaluate(適合「條件複雜但庫小」)、DQL 走結構化 query plan(適合「庫大、條件需高效」)
  • Domino 14 把 FTSearch 整合進 DQL — 用 @FTSearch('query') term 在 DQL 裡寫全文條件、跟其他結構化 term 用 Boolean operator 串
  • 沒有「全勝」選項 — 三者各有強項弱項、選錯成本可能差幾個數量級
  • 決策樹三個問題:庫多大?條件文字 vs 結構化?需不需要 ordering?— 三個答案組合決定走哪條
  • 常被忽略的組合策略:先 db.Search 用結構化條件縮範圍、再 collection.FTSearch 跑文字精篩、是中型庫的甜蜜點

三條路線的本質

下表的維度整理自 HCL 官方的 Collecting documents by searching conceptual page 跟三個 method 各自的 reference 頁。

維度FTSearchdb.SearchDQL
資料結構Full-text inverted index(單獨檔案 / 目錄)無、scan 文件本體Design catalog + NIF 索引 + 必要時 view re-use
Query 語言FT query string(AND/OR/NOT/CONTAINS/wildcards)@Formula(@Contains/@Modified/@IsAvailable 等)DQL(SQL-like、'view'.column = X
適合的條件型態文字內容搜尋任意 @Formula 邏輯結構化欄位過濾
效能模型O(matched terms)、Index lookupO(N) 全表 scanO(matched index entries)、走 explain plan
Index 成本FT index 占 disk、需要 admin 建無 index 需求Design catalog 需要維護、view-as-base 走 NIF
回傳順序預設按 relevance、可選 date sortUnsorted走 view 的話有 sort、bare-field 無 sort
max 結果預設 5000 cap、改 notes.ini真的無限真的無限
Live vs SnapshotSnapshot collectionSnapshot collectionSnapshot collection
可用 contextLotusScript / Java / SSJS / DQL termLotusScript / Java / SSJSLotusScript / Java / REST API / Notes Client F9
Reader 欄位處理套用(看不到沒權限的)套用bulk readers query 模式、效能提升

幾個關鍵觀察:

FTSearch 的相對位置

  • FTSearch 的純文字搜尋速度、relevance scoring、stem / thesaurus 支援
  • :結構化條件(Total > 1000)寫起來彆扭、5000 預設 cap、依賴 FT index 維護
  • 甜蜜點:搜尋 free-text 欄位(Subject / Body / Comments 等)、回相關性最高的 top-N

db.Search 的相對位置

  • db.Search 不需 index、formula 表達力強、dateTime cursor 適合增量處理
  • :O(N) 效能、不能寫 UI / lookup 類 @function、結果 unsorted
  • 甜蜜點:admin 不配合建 index 的舊系統、低頻 ad-hoc 查詢、scheduled agent 走增量處理

DQL 的相對位置

  • :大表效能、SQL-like 可讀性、'view'.column 走 NIF index、explain plan 可調效能、reader 欄位透過 bulk query 模式優化
  • :catalog 維護、有 Domino 12+ 版本門檻、某些 @function 不支援、調效能需要懂 explain plan
  • 甜蜜點:高頻結構化查詢、REST API 後端、大型 NSF(百萬份文件等級)

DQL 本身的細節在 DQL 三部曲(入門 / 踩雷 / 上 production)有完整三篇深入、本文不重複。


決策樹 — 三個問題定路徑

庫多大?
├─ 小(<10K 文件)
│ └─ 條件型態?
│ ├─ 純文字 → FTSearch
│ └─ 結構化 → db.Search
├─ 中(10K-100K 文件)
│ └─ 查詢頻率?
│ ├─ 高頻(>10 次/分)→ DQL
│ └─ 低頻 / 一次性 → 任意、但偏好 DQL
└─ 大(>100K 文件)
└─ 條件型態?
├─ 純文字 → FTSearch(必須有 index)
├─ 結構化 → DQL
└─ 兩者皆有 → DQL + @FTSearch term

這棵樹是 first-order heuristic、實務上還要考慮:

  • 是否能建 FT index — admin 政策 / disk 限制可能直接砍掉 FTSearch 選項
  • 是否走 REST API — 那必然 DQL(Domino REST API 後端就是 DQL)
  • 是否需要 ordering — FTSearch 內建 relevance / date sort 很省事、其他兩條要自己處理

Domino 14 的整合:DQL @FTSearch()

Domino 14 把 FTSearch 整合進 DQL — 用 @FTSearch('query') (也可寫 @FTS(...))作為 DQL term、跟結構化條件用 Boolean 串接:

@FTSearch('urgent') AND Status = 'Open'
IN ALL ('CustomersByCountry') OR @FTS('[name] < (b)')
@FTSearch('[TextField1] = (hello)') AND DateField1 > @dt('2026-06-12T04:17:31-04:00')

幾個重要規則(直接引用官方文件):

  • 「The function name is case-insensitive.」— @FTSearch@FTS 都可
  • 「@FTSearch() is a standalone term that returns the set of documents which matches the given full-text query, meaning that you cannot use any operators after it, only Booleans.」— @FTSearch(...) >= 100 是無效語法、要把比較條件單獨寫成另一個 term 再 AND
  • 「The maximum query string size is 256 bytes.」— 內層 FT query 字串有長度限制
  • 「The syntax rules … is the same as the FTSearch() function in LotusScript/Java classes and the C API」— 你在 Part 1 學到的 query syntax operators 在這裡通用

這個整合的意義是 不必再為「文字 + 結構化條件」寫 two-step chain(先 db.Search 再 collection.FTSearch、或先 FTSearch 再 LotusScript filter)— 一個 DQL query 表達完整。

但要注意:DQL @FTSearch 仍然依賴 FT index、沒 index 不會自動降級成 scan。可以用 db.IsFTIndexed 在 production code 預先檢查、不然 admin 端的 index 維護仍是先決條件。


三個實戰場景對照

場景 1:一次性 ad-hoc 查詢

「客服跟我說有客戶投訴上週寄出的訂單沒收到、幫我找一下」

' 走 db.Search 直接、條件清楚、跑一次就完事
Dim cutoff As New NotesDateTime("")
Call cutoff.SetNow()
Call cutoff.AdjustDay(-7)
Set docs = db.Search( _
"Type = ""Order"" & @Contains(CustomerEmail; ""@" & customerDomain & """)", _
cutoff, 0)

為什麼選 db.Search:

  • 一次性、不在乎效能 O(N)
  • 條件包含 @Contains 走文字、又有結構化 Type =
  • 不想為這次查詢建 FT index

場景 2:scheduled agent 處理新文件

「每 30 分鐘、把新進的 high-priority 訂單推到外部系統」

' 走 db.Search + dateTime cursor、增量處理
Set docs = db.Search( _
"Type = ""Order"" & Priority = ""High"" & Status = ""New""", _
lastRunCursor, 0)
' ...如 Part 2 incremental agent 範例

為什麼選 db.Search:

  • dateTime cursor 是天然的增量游標
  • 每次跑只看增量、O(N_new) 不是 O(N_total)
  • 條件結構化、formula 寫起來順

場景 3:高頻 REST API 後端

「客戶 portal 的搜尋頁、預期 1000+ req/min、要支援 keyword 跟 filter 組合」

@FTSearch('keyword') AND Status = 'Open' AND Total > 1000

為什麼選 DQL @FTSearch term:

  • 高頻 → 不能 O(N) scan
  • keyword 走 FT index 快、filter 走 NIF index 快
  • 用一個 DQL query 表達完整、不用 two-step chain
  • Domino REST API 後端原生就是 DQL

三條路線都不選的情境

有時候應該重新檢視「要不要 search」這個前提:

  • 如果是固定 key 查單筆 — 用 db.GetDocumentByUNID()view.GetDocumentByKey()、別 search
  • 如果是 view 已經 sort / filter 好的列表 — 直接走 view navigator / view entry collection、NotesViewNavigator 那條更快(見 NotesViewNavigator 文章
  • 如果是要走 REST API、又不是 Domino REST API — 上層 wrap 一層 cache 可能比每次都 search 更務實

Search 不是越用越好 — 每多一層 search 就是一次「掃 NoteID 集合」的成本。本系列三篇是「真的需要 search 時、怎麼選」的指南、不是「凡事都 search」的鼓勵。


系列結語

這套搜尋三部曲跟之前的 DQL 三部曲放在一起、Domino 文件搜尋的 surface 就算完整覆蓋了:

系列主題
Part 1: FTSearch文字索引的三層 API
Part 2: db.Search@Formula 暴力搜尋
Part 3: 三選一決策(本篇)對比 + 決策樹 + DQL @FTSearch 整合
DQL 入門SQL-like query 語法
DQL 踩雷寫 query 時 6 個細節
DQL Productioncatalog / permissions / sessionAsSigner

寫對的 search、效能差幾個數量級 — 選錯、就算優化 formula 也救不回來。本系列三篇加 DQL 三篇是把每條路的細節都攤開、實戰時依手上條件對表查就好。

參考來源

← 回到文章列表