外部索引和搜尋

簡介

從 1.8.3 版本開始,Doxygen 提供了使用外部索引工具和搜尋引擎來搜尋 HTML 的能力。這有幾個優點

  • 對於大型專案,相較於 Doxygen 的內建搜尋引擎,它具有顯著的效能優勢,因為 Doxygen 使用的是相當簡單的索引演算法。
  • 它允許將多個專案的搜尋資料組合到一個索引中,從而允許跨多個 Doxygen 專案進行全域搜尋。
  • 它允許將其他資料添加到搜尋索引中,例如不是由 Doxygen 產生的其他網頁。
  • 搜尋引擎需要在網頁伺服器上執行,但用戶仍然可以在本地瀏覽網頁。

為了避免每個人都必須開始編寫自己的索引器和搜尋引擎,Doxygen 為每個動作提供了一個範例工具:用於索引資料的 doxyindexer 和用於搜尋索引的 doxysearch.cgi

資料流程如下圖所示

外部搜尋資料流程
  • doxygen 產生原始搜尋資料
  • doxyindexer 將資料索引到搜尋資料庫 doxysearch.db
  • 當使用者從 Doxygen 產生的 HTML 頁面執行搜尋時,將會調用 CGI 二進制檔 doxysearch.cgi
  • doxysearch.cgi 工具將對資料庫執行查詢並返回結果。
  • 瀏覽器將顯示搜尋結果。

設定

第一步是透過網頁伺服器使搜尋引擎可用。如果您使用 doxysearch.cgi,這表示使 CGI 二進制檔可從網頁伺服器存取(即能夠透過以 http: 開頭的 URL 從瀏覽器執行它)

如何設定網頁伺服器不在本文檔的範圍內,但如果您例如安裝了 Apache,您可以簡單地將 doxysearch.cgi 檔案從 Doxygen 的 bin 目錄複製到 Apache 網頁伺服器的 cgi-bin 目錄。請閱讀 apache 文件以取得詳細資訊。

若要測試 doxysearch.cgi 是否可存取,請啟動您的網頁瀏覽器並指向二進制檔的 URL,並在結尾新增 ?test

http://yoursite.com/path/to/cgi/doxysearch.cgi?test

您應該會收到以下訊息

Test failed: cannot find search index doxysearch.db

如果您使用 Internet Explorer,可能會提示您下載檔案,然後該檔案將包含此訊息。

由於我們沒有建立或安裝 doxysearch.db,因此測試因這個原因而失敗是正常的。下一節將討論如何更正此問題。

在繼續下一節之前,請將上述 URL(不包含 ?test 部分)新增至 Doxygen 組態檔案中的 SEARCHENGINE_URL 標籤

SEARCHENGINE_URL = http://yoursite.com/path/to/cgi/doxysearch.cgi

單一專案索引

若要使用外部搜尋選項,請確定在 Doxygen 組態檔案中啟用以下選項

SEARCHENGINE           = YES
SERVER_BASED_SEARCH    = YES
EXTERNAL_SEARCH        = YES

這將使 Doxygen 在輸出目錄中產生一個名為 searchdata.xml 的檔案(使用 OUTPUT_DIRECTORY 設定)。您可以使用 SEARCHDATA_FILE 選項變更檔案名稱(和位置)。

下一步是將原始搜尋資料放入索引中以便進行有效率的搜尋。您可以使用 doxyindexer 來執行此操作。只需從命令列執行它即可

doxyindexer searchdata.xml

這將建立一個名為 doxysearch.db 的目錄,其中包含一些檔案。預設情況下,該目錄將建立在啟動 doxyindexer 的位置,但您可以使用 -o 選項來變更目錄。

doxysearch.db 目錄複製到 doxysearch.cgi 所在的相同目錄,然後透過將瀏覽器指向來重新執行瀏覽器測試

http://yoursite.com/path/to/cgi/doxysearch.cgi?test

您現在應該會收到以下訊息

Test successful.

現在您應該可以從 HTML 輸出中搜尋單字和符號。

多專案索引

如果您有多個 Doxygen 專案,並且這些專案相關,則可能希望允許從任何專案的文件中搜尋所有專案中的單字。

若要實現此目的,只需將所有專案的搜尋資料組合到一個索引中即可,例如,對於兩個專案 A 和 B,它們的 searchdata.xml 分別在目錄 project_A 和 project_B 中產生,請執行

doxyindexer project_A/searchdata.xml project_B/searchdata.xml

然後將產生的 doxysearch.db 複製到 doxysearch.cgi 所在的目錄。

searchdata.xml 檔案不包含任何絕對路徑或連結,那麼如何將多個專案的搜尋結果連結回正確的文件集?這就是 EXTERNAL_SEARCH_IDEXTRA_SEARCH_MAPPINGS 選項的作用。

為了能夠識別不同的專案,需要使用 EXTERNAL_SEARCH_ID 為每個專案設定唯一的 ID。

若要將搜尋結果連結到正確的專案,您需要使用 EXTRA_SEARCH_MAPPINGS 標籤為每個專案定義一個對應。使用此選項,您可以定義從其他專案的 ID 到這些專案文件(相對)位置的對應。

因此,對於專案 A 和 B,組態檔案的相關部分可能如下所示

project_A/Doxyfile
------------------
EXTERNAL_SEARCH_ID    = A
EXTRA_SEARCH_MAPPINGS = B=../../project_B/html

對於專案 A 和專案 B

project_B/Doxyfile
------------------
EXTERNAL_SEARCH_ID    = B
EXTRA_SEARCH_MAPPINGS = A=../../project_A/html

透過這些設定,專案 A 和 B 可以共用相同的搜尋資料庫,並且搜尋結果將連結到正確的文件集。

更新索引

當您修改原始碼時,您應該重新執行 doxygen 以再次取得最新的文件。使用外部搜尋時,您也需要透過重新執行 doxyindexer 來更新搜尋索引。您可以將呼叫 doxygendoxyindexer 包裝在腳本中,以使此過程更容易。

程式設計介面

先前的章節假設您使用工具 doxyindexerdoxysearch.cgi 進行索引和搜尋,但是如果您願意,您也可以編寫自己的索引和搜尋工具。

為此,有 3 個介面很重要

  • 索引工具的輸入格式。
  • 搜尋引擎的輸入格式。
  • 搜尋引擎的輸出格式。

以下小節將更詳細地描述這些介面。

索引器輸入格式

Doxygen 產生的搜尋資料遵循 Solr XML 索引訊息格式。

索引器的輸入是一個 XML 檔案,其中包含一個 <add> 標籤,該標籤包含多個 <doc> 標籤,而這些標籤又包含多個 <field> 標籤。

以下是一個 doc 節點的範例,其中包含一個方法的搜尋資料和中繼資料

<add>
  ...
  <doc>
    <field name="type">function</field>
    <field name="name">QXmlReader::setDTDHandler</field>
    <field name="args">(QXmlDTDHandler *handler)=0</field>
    <field name="tag">qtools.tag</field>
    <field name="url">de/df6/class_q_xml_reader.html#a0b24b1fe26a4c32a8032d68ee14d5dba</field>
    <field name="keywords">setDTDHandler QXmlReader::setDTDHandler QXmlReader</field>
    <field name="text">Sets the DTD handler to handler DTDHandler()</field>
  </doc>
  ...
</add>

每個欄位都有一個名稱。支援下列欄位名稱

  • type:搜尋項目的類型;可以是下列其中之一:source、function、slot、signal、variable、typedef、enum、enumvalue、property、event、related、friend、define、file、namespace、concept、group、package、page、dir、module、constants、library、type、union、interface、protocol category、exception、class、struct、service、singleton
  • name:搜尋項目的名稱;對於方法,這是方法的限定名稱;對於類別,這是類別的名稱,依此類推。
  • args:參數清單(針對函式或方法)
  • tag:用於此專案的標籤檔案的名稱。
  • url:此項目的 HTML 文件(相對)URL。
  • keywords:代表項目的重要單字。當搜尋此類關鍵字時,此項目在搜尋結果中的排名應更高。
  • text:與項目相關的文件。請注意,僅存在單字,沒有標記。
注意
由於 XML 檔案可能很大,建議使用 基於 SAX 的剖析器來處理它。

搜尋 URL 格式

當從 Doxygen 產生的 HTML 頁面調用搜尋引擎時,會透過 查詢字串傳遞多個參數。

會傳遞下列欄位

  • q:使用者輸入的查詢文字
  • n:要求的搜尋結果數。
  • p:要傳回結果的搜尋頁碼。每個頁面都有 n 個值。
  • cb:回呼函式的名稱,用於具有填補的 JSON,請參閱下一節。

從完整的搜尋結果清單中,應傳回範圍 [n*p - n*(p+1)-1]

以下是查詢的外觀範例。

http://yoursite.com/path/to/cgi/doxysearch.cgi?q=list&n=20&p=1&cb=dummy

它代表對單字「list」(q=list)的查詢,要求 20 個搜尋結果(n=20),從結果編號 20(p=1)開始,並使用回呼「dummy」(cb=dummy

注意
這些值是 URL 編碼的,因此必須先將它們解碼才能使用。

搜尋結果格式

當如先前小節所示調用搜尋引擎時,它應回覆結果。回覆的格式是 具有填補的 JSON,它基本上是一個包裝在函式呼叫中的 JavaScript 結構。函式的名稱應為回呼的名稱(如查詢中的 cb 欄位所傳遞)。

對於如先前小節所示的範例查詢,回覆的主要結構應如下所示

dummy({
  "hits":179,
  "first":20,
  "count":20,
  "page":1,
  "pages":9,
  "query": "list",
  "items":[
  ...
 ]})

這些欄位具有下列含義

  • hits:搜尋結果的總數(可能多於要求的數目)。
  • first:傳回的第一個結果的索引:$\min(n*p,\mbox{\em hits})$
  • count:傳回的實際結果數:$\min(n,\mbox{\em hits}-\mbox{\em first})$
  • page:結果的頁碼:$p$
  • pages:頁面的總數:$\left\lceil\frac{\mbox{\em hits}}{n}\right\rceil$
  • items:包含每個結果搜尋資料的陣列。

以下是 items 陣列的元素的外觀範例

{"type": "function",
 "name": "QDir::entryInfoList(const QString &nameFilter, int filterSpec=DefaultFilter, int sortSpec=DefaultSort) const",
 "tag": "qtools.tag",
 "url": "d5/d8d/class_q_dir.html#a9439ea6b331957f38dbad981c4d050ef",
 "fragments":[
   "Returns a <span class=\"hl\">list</span> of QFileInfo objects for all files and directories...",
   "... pointer to a QFileInfoList The <span class=\"hl\">list</span> is owned by the QDir object...",
   "... to keep the entries of the <span class=\"hl\">list</span> after a subsequent call to this..."
 ]
},

此類項目的欄位具有下列含義

  • type:項目的類型,如原始搜尋資料中名稱為「type」的欄位中所找到的。
  • name:項目的名稱,包括參數清單,如原始搜尋資料中名稱為「name」和「args」的欄位中所找到的。
  • tag:標籤檔案的名稱,如同在原始搜尋資料中,名稱為 "tag" 的欄位中所找到的。
  • url:文件(相對)URL 的名稱,如同在原始搜尋資料中,名稱為 "url" 的欄位中所找到的。
  • "fragments":一個陣列,包含 0 個或多個含有被搜尋文字的文本片段。這些文字應以 <span class="hl"></span> 標籤包覆,以便在輸出中將其高亮顯示。