外部索引和搜索

简介

自1.8.3版本发布以来,Doxygen提供了使用外部索引工具和搜索引擎搜索HTML的能力。这有几个优点:

  • 对于大型项目,它可能比Doxygen的内置搜索引擎具有显著的性能优势,因为Doxygen使用相对简单的索引算法。
  • 它允许将多个项目的搜索数据组合到一个索引中,从而实现跨多个Doxygen项目的全局搜索。
  • 它允许向搜索索引添加额外的数据,即不由Doxygen生成的其他网页。
  • 搜索引擎需要在Web服务器上运行,但客户端仍然可以在本地浏览网页。

为了避免每个人都必须开始编写自己的索引器和搜索引擎,Doxygen为每个操作提供了一个示例工具:doxyindexer 用于索引数据,doxysearch.cgi 用于搜索索引。

数据流如下图所示:

外部搜索数据流
  • doxygen 生成原始搜索数据
  • doxyindexer 将数据索引到搜索数据库 doxysearch.db
  • 当用户从Doxygen生成的HTML页面执行搜索时,将调用CGI二进制文件 doxysearch.cgi
  • doxysearch.cgi 工具将对数据库执行查询并返回结果。
  • 浏览器将显示搜索结果。

配置

第一步是通过Web服务器使搜索引擎可用。如果您使用 doxysearch.cgi,这意味着使 CGI 二进制文件可从Web服务器获得(即能够通过以http:开头的URL从浏览器运行它)

如何设置Web服务器超出了本文档的范围,但是如果您安装了Apache,您可以简单地将Doxygen的 bin 目录中的 doxysearch.cgi 文件复制到Apache Web服务器的 cgi-bin 目录。有关详细信息,请阅读 apache文档

要测试 doxysearch.cgi 是否可访问,请启动您的Web浏览器并指向二进制文件的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在输出目录(通过 OUTPUT_DIRECTORY 配置)中生成一个名为 searchdata.xml 的文件。您可以使用 SEARCHDATA_FILE 选项更改文件名(和位置)。

下一步是将原始搜索数据放入索引中以进行高效搜索。您可以使用 doxyindexer。只需从命令行运行它:

doxyindexer searchdata.xml

这将创建一个名为 doxysearch.db 的目录,其中包含一些文件。默认情况下,该目录将创建在 doxyindexer 启动的位置,但您可以使用 -o 选项更改目录。

doxysearch.db 目录复制到 doxysearch.cgi 所在的同一目录,并通过将浏览器指向以下URL来重新运行浏览器测试:

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> 标签,而 <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> 标签中,以便在输出中突出显示它们。