使用所有 SQL 驱动程序,构建一个普通表通常按以下方式进行。
- 建立与数据库的连接。
- 执行
sql_query_pre_all查询以进行任何必要的初始设置,例如使用 MySQL 设置每个连接的编码。这些查询在整个索引过程之前执行,也在重新连接后执行,以索引 MVA 属性和联接字段。 - 执行
sql_query_pre预查询以进行任何必要的初始设置,例如设置临时表或维护计数器表。这些查询在整个索引过程只执行一次。 - 执行
sql_query_pre的预查询以进行任何必要的初始设置,例如设置临时 表,或维护计数器表。这些查询在整个索引过程中只执行一次。 - 执行主查询
sql_query,并处理它返回的行。 - 执行后查询
sql_query_post以进行必要的清理。 - 关闭与数据库的连接。
- 索引器执行排序阶段(严格来说,是表类型特定的后处理)。
- 再次建立与数据库的连接。
- 执行后处理查询
sql_query_post_index以进行必要的最终清理。 - 再次关闭与数据库的连接。
从 MYSQL 获取数据的示例:
source mysource {
type = mysql
path = /path/to/realtime
sql_host = localhost
sql_user = myuser
sql_pass = mypass
sql_db = mydb
sql_query_pre = SET CHARACTER_SET_RESULTS=utf8
sql_query_pre = SET NAMES utf8
sql_query = SELECT id, title, description, category_id FROM mytable
sql_query_post = DROP TABLE view_table
sql_query_post_index = REPLACE INTO counters ( id, val ) \
VALUES ( 'max_indexed_id', $maxid )
sql_attr_uint = category_id
sql_field_string = title
}
table mytable {
type = plain
source = mysource
path = /path/to/mytable
...
}
这是用于从 SQL 服务器检索文档的查询。只能声明一个 sql_query,且必须有一个。另见 Processing fetched data
预取查询或预查询。这是一个多值的可选设置,默认是一个空的查询列表。预查询在 sql_query 之前按其在配置文件中的顺序执行。预查询的结果会被忽略。
预查询用途多样。它们可用于设置编码、标记将要被索引的记录、更新内部计数器、设置各种每连接的 SQL 服务器选项和变量,等等。
预查询最常见的用途可能是指定服务器返回行所用的编码。注意 Manticore 只接受 UTF-8 文本。设定编码的两个 MySQL 特定示例如下:
sql_query_pre = SET CHARACTER_SET_RESULTS=utf8
sql_query_pre = SET NAMES utf8
此外,特定于 MySQL 源,禁用查询缓存(仅限索引器连接)在预查询中很有用,因为索引查询不会频繁重跑,缓存它们的结果没有意义。 这可以通过以下方式实现:
sql_query_pre = SET SESSION query_cache_type=OFF
后取查询。此为可选设置,默认值为空。
此查询在 sql_query 成功完成后立即执行。后取查询如果出现错误,会以警告方式报告,但不会终止索引。它的结果集会被忽略。注意此时索引尚未完成,后续索引仍可能失败。因此,不应从这里执行任何永久更新。例如,永久改变最后成功索引 ID 的辅助表更新,不应从 sql_query_post 查询运行,而应从 sql_query_post_index 查询运行。
后处理查询。此为可选设置,默认值为空。
此查询在索引完全且成功完成时执行。如果此查询出现错误,会以警告方式报告,但不会终止索引。它的结果集会被忽略。文本中可以使用 $maxid 宏;它将被展开为索引期间实际从数据库获取的最大文档 ID。如果没有索引任何文档,$maxid 将被展开为 0。
示例:
sql_query_post_index = REPLACE INTO counters ( id, val ) \
VALUES ( 'max_indexed_id', $maxid )
sql_query_post 和 sql_query_post_index 的区别在于,sql_query_post 在 Manticore 接收到所有文档时立即运行,但后续索引可能因其他原因失败。相反,在执行 sql_query_post_index 查询时,表已确保成功创建。数据库连接会断开重建,因为排序阶段可能非常长,否则会超时。
默认情况下,sql_query结果集的第一列被索引为文档ID。
文档ID MUST 是非常第一个字段,并且 MUST BE 唯一的非零整数,范围从 -9223372036854775808 到 9223372036854775807。
你可以指定最多256个全文字段和任意数量的属性。所有既不是文档ID(第一个字段)也不是属性的列将被索引为全文字段。
声明一个64位 signed 整数。
声明一个布尔属性。它等同于一个位数为1的整数属性。
声明一个浮点属性。
值将以单精度,32位IEEE 754格式存储。表示范围大约是从1e-38到1e+38。可以精确存储的大约7位小数。
浮点属性的一个重要用途是存储以弧度表示的纬度和经度值,以便在查询时进行地理球体距离计算。
声明一个JSON属性。
在索引JSON属性时,Manticore期望一个包含JSON格式数据的文本字段。JSON属性支持任意JSON数据,没有嵌套级别或类型的限制。
声明一个多值属性。
普通属性仅允许每个文档附加一个值。然而,在某些情况下(如标签或类别),希望附加多个相同属性的值,并能够对值列表进行过滤或分组。
MVA可以从列中获取值(如其他数据类型一样)——在这种情况下,结果集中的列必须提供用逗号分隔的多个整数值的字符串——或者通过运行单独的查询来获取值。
在执行查询时,引擎会运行查询,按ID分组结果,并将值分配给表中的相应文档。ID未在表中找到的值将被丢弃。在执行查询之前,任何定义的 sql_query_pre_all 将被运行。
sql_attr_multi 的声明格式如下:
sql_attr_multi = ATTR-TYPE ATTR-NAME 'from' SOURCE-TYPE \
[;QUERY] \
[;RANGED-QUERY]
其中
- ATTR-TYPE 是
uint,bigint或timestamp。 - SOURCE-TYPE 是
field,query,ranged-query或ranged-main-query。 - QUERY 是一个可选的SQL查询,用于获取所有 (docid, attrvalue) 对。
- RANGED-QUERY 是一个可选的SQL查询,用于获取最小和最大ID值,类似于
sql_query_range。 - 退格符只是为了清晰而包含的;所有内容也可以在单行中声明。
它用于 ranged-query SOURCE-TYPE。如果使用 ranged-main-query SOURCE-TYPE,则省略 RANGED-QUERY,并将自动使用与 sql_query_range 相同的查询(在复杂的继承设置中很有用,可以节省手动多次复制相同查询的麻烦)。
sql_attr_multi = uint tag from field
sql_attr_multi = uint tag from query; SELECT id, tag FROM tags
sql_attr_multi = bigint tag from ranged-query; \
SELECT id, tag FROM tags WHERE id>=$start AND id<=$end; \
SELECT MIN(id), MAX(id) FROM tags
声明一个字符串属性。每个值的最大大小固定为4GB。
声明一个UNIX时间戳。
时间戳可以存储从1970年1月1日到2038年1月19日之间的日期和时间,精度为一秒。预期的列值应为UNIX格式的时间戳,即自1970年1月1日格林尼治标准时间午夜以来的32位无符号整数秒数。时间戳在内部以整数形式存储和处理。除了以整数形式处理时间戳外,还可以使用不同的日期函数,如时间段排序模式或使用 GROUP BY 进行日/周/月/年提取。
请注意,MySQL中的DATE或DATETIME列不能直接用作Manticore的时间戳属性;需要显式使用UNIX_TIMESTAMP函数(如果数据在范围内)进行转换。
请注意,时间戳不能表示1970年1月1日之前的日期,而MySQL中的UNIX_TIMESTAMP()将不会返回预期的结果。如果你只需要处理日期,而不是时间,可以考虑使用MySQL中的TO_DAYS()函数。
声明一个无符号整数属性。
可以通过在属性名称后附加 :BITCOUNT 来指定整数属性的位数(参见下面的示例)。具有小于默认32位大小或位字段的属性会变慢。
sql_attr_uint = group_id
sql_attr_uint = forum_id:9 # 9 bits for forum_id
声明一个组合字符串属性/文本字段。值将作为全文字段索引,但也会以相同名称存储在字符串属性中。请注意,只有在确定希望该字段以全文方式和属性方式(具有排序和分组的能力)进行搜索时,才应使用此功能。如果你只是想获取字段的原始值,除非你隐式地通过 stored_fields 从存储字段列表中删除了该字段,否则不需要为此做任何操作。
sql_field_string = name
声明一个基于文件的字段。
此指令使索引器将字段内容解释为文件名,并加载和处理所引用的文件。大小超过 max_file_field_buffer 的文件将被跳过。在文件加载过程中(I/O错误、超出限制等)发生的任何错误将作为索引警告报告,并不会提前终止索引。此类文件不会被索引内容。
sql_file_field = field_name
联合/负载字段获取查询。多值,可选,默认为空查询列表。
sql_joined_field 允许使用两种不同的功能:联合字段和负载(负载字段)。其语法如下:
sql_joined_field = FIELD-NAME 'from' ( 'query' | 'payload-query' | 'ranged-query' | 'ranged-main-query' ); \
QUERY [ ; RANGE-QUERY ]
其中
- FIELD-NAME 是联合/负载字段名称
- QUERY 是一个必须获取进一步处理值的SQL查询
- RANGE-QUERY 是一个可选的SQL查询,用于获取要处理的值范围
Joined fields 让您避免在主文档查询(sql_query)中使用 JOIN 和/或 GROUP_CONCAT 语句。当 SQL 端的 JOIN 慢,或需要卸载到 Manticore 端,或者仅仅是为了模拟 MySQL 特定的 GROUP_CONCAT 功能(以防您的数据库服务器不支持该功能)时,这会很有用。
查询必须恰好返回 2 列:文档 ID 和要追加到已连接字段的文本。文档 ID 可以重复,但必须是升序。对于给定 ID 获取的所有文本行将被串联在一起,串联结果将作为已连接字段的全部内容进行索引。行将按照查询返回的顺序连接,并在它们之间插入分隔空白字符。例如,如果已连接字段查询返回如下行:
( 1, 'red' )
( 1, 'right' )
( 1, 'hand' )
( 2, 'mysql' )
( 2, 'manticore' )
那么索引结果将等同于为文档 1 添加一个新文本字段,其值为 'red right hand',为文档 2 添加一个新文本字段,其值为 'mysql sphinx',其中包括关键字在字段内按照查询顺序出现的位置。如果需要特定顺序,必须在查询中明确指定。
已连接字段只在索引方式上有所不同。已连接字段和常规文本字段之间没有其他区别。
在执行已连接字段查询之前,如果存在任何 sql_query_pre_all 集合,将会被执行。这允许您在已连接字段上下文内设置所需的编码等。
当单个查询效率不够高或由于数据库驱动程序限制而无法工作时,可以使用范围查询。它的工作方式类似于主索引循环中的范围查询。区间将被预先查询并获取一次,然后执行多个带有不同 $start 和 $end 替换的查询以获取实际数据。
使用 ranged-main-query 查询时,省略 ranged-query,它将自动使用 sql_query_range 中的相同查询(在复杂继承设置中非常有用,可以避免手动多次复制相同的查询)。
Payloads 允许您创建一个特殊字段,其中不存储关键字位置,而是存储所谓的用户负载。负载是附加到每个关键字的自定义整数值。然后可以在搜索时用于影响排名。
负载查询必须返回恰好 3 列:
- 文档 ID
- 关键字
- 整数负载值。
文档 ID 可以重复,但必须是升序。负载必须是 24 位范围内的无符号整数,即从 0 到 16777215。
唯一考虑负载的排序器是 proximity_bm25(默认 ranker)。对于具有负载字段的表,它会自动切换到一个变体,该变体匹配这些字段中的关键字,计算匹配负载乘以字段权重的总和,并将该总和加到最终排名中。
请注意,负载字段会被包含复杂操作符的全文查询忽略。它仅适用于简单的词袋查询。
- Configuration file
- Just SELECT
- Full-text search
- Complex full-text search
source min {
type = mysql
sql_host = localhost
sql_user = test
sql_pass =
sql_db = test
sql_query = select 1, 'Nike bag' f \
UNION select 2, 'Adidas bag' f \
UNION select 3, 'Reebok bag' f \
UNION select 4, 'Nike belt' f
sql_joined_field = tag from payload-query; select 1 id, 'nike' tag, 10 weight \
UNION select 4 id, 'nike' tag, 10 weight;
}
index idx {
path = idx
source = min
}mysql> select * from idx;
+------+------------+------+
| id | f | tag |
+------+------------+------+
| 1 | Nike bag | nike |
| 2 | Adidas bag | |
| 3 | Reebok bag | |
| 4 | Nike belt | nike |
+------+------------+------+
4 rows in set (0.00 sec)请注意,当您搜索 nike | adidas 时,结果中包含 "nike" 的部分因为来自负载查询的 "nike" 标签及其权重而获得更高权重。
mysql> select *, weight() from idx where match('nike|adidas');
+------+------------+------+----------+
| id | f | tag | weight() |
+------+------------+------+----------+
| 1 | Nike bag | nike | 11539 |
| 4 | Nike belt | nike | 11539 |
| 2 | Adidas bag | | 1597 |
+------+------------+------+----------+
3 rows in set (0.01 sec)请注意,特殊的负载字段会被包含复杂操作符的全文查询忽略。它仅适用于简单的词袋查询。
mysql> select *, weight() from idx where match('"nike bag"|"adidas bag"');
+------+------------+------+----------+
| id | f | tag | weight() |
+------+------------+------+----------+
| 2 | Adidas bag | | 2565 |
| 1 | Nike bag | nike | 2507 |
+------+------------+------+----------+
2 rows in set (0.00 sec)sql_column_buffers = <colname>=<size>[K|M] [, ...]
每列缓冲大小。可选,默认为空(自动推断大小)。仅适用于 odbc,mssql 源类型。
ODBC 和 MS SQL 驱动程序有时无法返回预期的最大实际列大小。例如,NVARCHAR(MAX) 列总是向 indexer 报告其长度为 2147483647 字节,即使实际使用的长度可能远小于此。然而,接收缓冲区仍需预先分配且大小必须确定。当驱动程序根本不报告列长度时,Manticore 会为每个非字符列分配默认的 1 KB 缓冲区,为每个字符列分配 1 MB 缓冲区。驱动程序报告的列长度也会被限制在 8 MB 的上限,因此如果驱动程序报告(几乎)2 GB 的列长度,它会被限制,并为该列分配 8 MB 缓冲区。可以通过 sql_column_buffers 指令覆盖这些硬编码限制,以节省实际较短列的内存或突破 8 MB 限制以支持实际更长列。指令值必须为逗号分隔的选定列名和大小列表:
示例:
sql_query = SELECT id, mytitle, mycontent FROM documents
sql_column_buffers = mytitle=64K, mycontent=10M
主要查询,需要获取所有文档时,可能会对整个表施加读锁并阻塞并发查询(例如,MyISAM 表的 INSERT 操作),浪费大量内存用于结果集等。为了避免这种情况,Manticore 支持所谓的 范围查询。使用范围查询时,Manticore 首先从表中获取最小和最大文档 ID,然后将不同的 ID 区间插入到主查询文本中,并运行修改后的查询以获取另一批文档。这里有一个例子。
范围查询使用示例:
sql_query_range = SELECT MIN(id),MAX(id) FROM documents
sql_range_step = 1000
sql_query = SELECT * FROM documents WHERE id>=$start AND id<=$end
如果表包含从 1 到,比如说,2345 的文档 ID,那么 sql_query 将会运行三次:
- 用
$start替换为 1 并用$end替换为 1000; - 用
$start替换为 1001 并用$end替换为 2000; - 用
$start替换为 2001 并用$end替换为 2345。
显然,对于 2000 行的表来说这不是很大的区别,但当涉及到索引 10 百万行的表时,范围查询可能会有所帮助。
定义范围查询。此选项指定的查询必须获取将用作范围边界的最小和最大文档 ID。它必须返回恰好两个整数字段,最小 ID 先,最大 ID 后;字段名被忽略。启用时,sql_query 必须包含 $start 和 $end 宏。请注意,由 $start..$end 指定的区间不会重叠,因此在您的查询中不应删除等于 $start 或 $end 的文档 ID。
此指令定义了范围查询步长。默认值是 1024。
此指令可以用来限制范围查询的速度。默认情况下,没有限制。sql_ranged_throttle 的值应以毫秒为单位指定。
限制范围查询速度可能在索引器对数据库服务器施加过多负载时很有用。这会导致索引器在每个范围查询步骤后睡眠一段时间。这种睡眠是无条件的,在执行获取查询之前进行。
sql_ranged_throttle = 1000 # sleep for 1 sec before each query step
xmlpipe2 源类型允许用自定义的 XML 格式将自定义全文和属性数据传递给 Manticore,模式(即字段和属性集)可以在 XML 流本身或源设置中指定。
要声明 XML 流,xmlpipe_command 指令是必须的,它包含生成要索引的 XML 流的 shell 命令。该命令可以是一个文件,也可以是一个实时生成 XML 内容的程序。
当索引 xmlpipe2 源时,索引器运行指定的命令,打开到其 stdout 的管道,并期望获得格式良好的 XML 流。
下面是 XML 流数据的示例:
<?xml version="1.0" encoding="utf-8"?>
<sphinx:docset>
<sphinx:schema>
<sphinx:field name="subject"/>
<sphinx:field name="content"/>
<sphinx:attr name="published" type="timestamp"/>
<sphinx:attr name="author_id" type="int" bits="16" default="1"/>
</sphinx:schema>
<sphinx:document id="1234">
<content>this is the main content <![CDATA[and this <cdata> entry
must be handled properly by xml parser lib]]></content>
<published>1012325463</published>
<subject>note how field/attr tags can be
in <b> class="red">randomized</b> order</subject>
<misc>some undeclared element</misc>
</sphinx:document>
<sphinx:document id="1235">
<subject>another subject</subject>
<content>here comes another document, and i am given to understand,
that in-document field order must not matter, sir</content>
<published>1012325467</published>
</sphinx:document>
<!-- ... even more sphinx:document entries here ... -->
<sphinx:killlist>
<id>1234</id>
<id>4567</id>
</sphinx:killlist>
</sphinx:docset>
允许任意字段和属性。它们在流中每个文档内的顺序也可以是任意的;顺序会被忽略。字段长度有限制;超过 2 MB 的字段将被截断到 2 MB(此限制可在源中更改)。
模式,即完整的字段和属性列表,必须在任何文档解析之前声明。可以通过配置文件中的 xmlpipe_field 和 xmlpipe_attr_XXX 设置声明,也可以直接在流中使用 <sphinx:schema> 元素声明。<sphinx:schema> 是可选的。它只能作为 <sphinx:docset> 中的第一个子元素出现。如果流中没有模式定义,则使用配置文件中的设置。否则,流中的设置优先。注意文档 ID 应作为 <sphinx:document> 标签的属性 id 指定(例如 <sphinx:document id="1235">),并且应是唯一的正的非零 64 位整数。
未知标签(既未声明为字段也未声明为属性)将被忽略并发出警告。上面示例中的 <misc> 将被忽略。所有嵌套的标签及其属性(如上例中 <subject> 中的 <strong>)将被静默忽略。
对输入流编码的支持取决于系统上是否安装了 iconv。xmlpipe2 使用 libexpat 解析器解析,它原生支持 US-ASCII、ISO-8859-1、UTF-8 和几种 UTF-16 变体。Manticore 的 configure 脚本还会检测 libiconv 的存在,并利用其处理其他编码。libexpat 还强制要求 Manticore 侧使用 UTF-8 字符集,因为它返回的解析数据总是 UTF-8。
xmlpipe2 识别的 XML 元素(标签)及其适用的属性有:
sphinx:docset- 必须的顶层元素,表示并包含 xmlpipe2 文档集。sphinx:schema- 可选元素,必须是 sphinx:docset 的第一个子元素或根本不出现。声明文档模式,包含字段和属性声明。如果存在,它将覆盖配置文件中的每个源设置。sphinx:field- 可选元素,sphinx:schema 的子元素。声明全文字段。已知属性:- "name",指定将被视为全文字段的 XML 元素名。
- "attr",指定是否还将此字段索引为字符串。可能的值为 "string"。
sphinx:attr- 可选元素,sphinx:schema 的子元素。声明属性。已知属性:- "name",指定应被视为文档属性的元素名。
- "type",指定属性类型。可能的值有 "int"、"bigint"、"timestamp"、"bool"、"float"、"multi" 和 "json"。
- "bits",指定 "int" 类型属性的位数。有效值为 1 到 32。
- "default",指定如果文档中不存在该属性元素时应使用的默认值。
sphinx:document- 必须元素,必须是 sphinx:docset 的子元素。包含声明的字段和属性值的任意其他元素,用于索引。声明方式要么使用 sphinx:field 和 sphinx:attr 元素,要么在配置文件中声明。唯一已知的属性是 "id",必须包含唯一的整数文档 ID。sphinx:killlist- 可选元素,sphinx:docset 的子元素。包含若干 "id" 元素,其内容是属于待从表中删除的文档 ID。杀死列表用于多表搜索中抑制搜索结果中其他表中的文档。
如果 XML 没有定义模式,表元素的数据类型必须在源配置中定义。
xmlpipe_field- 声明一个text字段。xmlpipe_field_string- 声明一个文本字段/字符串属性。该列既被索引为文本字段,也被存储为字符串属性。xmlpipe_attr_uint- 声明一个整数属性。xmlpipe_attr_timestamp- 声明一个时间戳属性。xmlpipe_attr_bool- 声明一个布尔属性。xmlpipe_attr_float- 声明一个浮点属性。xmlpipe_attr_bigint- 声明一个大整数属性。xmlpipe_attr_multi- 声明一个多值整数属性。xmlpipe_attr_multi_64- 声明一个 64 位整数的多值属性。xmlpipe_attr_string- 声明一个字符串属性。xmlpipe_attr_json- 声明一个 JSON 属性。
如果设置了 xmlpipe_fixup_utf8,将启用 Manticore 端的 UTF-8 验证和过滤,以防止 XML 解析器因非 UTF-8 文档而出错。默认情况下,此选项禁用。
在某些情况下,可能很难甚至不可能保证传入的 XMLpipe2 文档主体是完全有效且符合规范的 UTF-8 编码。例如,带有国家单字节编码的文档可能会混入数据流中。libexpat XML 解析器比较脆弱,意味着在这种情况下它会停止处理。UTF8 修正功能可以让你避免这种情况。当启用修正时,Manticore 会在将传入流传递给 XML 解析器之前对其进行预处理,并将无效的 UTF-8 序列替换为空格。
xmlpipe_fixup_utf8 = 1
未在配置中定义模式的 XML 源示例:
source xml_test_1
{
type = xmlpipe2
xmlpipe_command = cat /tmp/products_today.xml
}
在配置中定义了模式的 XML 源示例:
source xml_test_2
{
type = xmlpipe2
xmlpipe_command = cat /tmp/products_today.xml
xmlpipe_field = subject
xmlpipe_field = content
xmlpipe_attr_timestamp = published
xmlpipe_attr_uint = author_id:16
}