3.1.数据源
索引的数据可以来自各种各样不同的来源:SQL数据库、纯文本、HTML文件、邮件等等。从Sphinx的视角看,索引数据是一个结构化的文档的集合,其中每个文档是字段的集合,这和SQL数据库的视角有所不同,在那里,每一行代表一个文档,每一列代表一个字段。
由于数据来源的不同,需要不同的代码来获取数据、处理数据以供Sphinx进行索引的建立。这种代码被称之为数据源驱动程序(简称:驱动或数据源)。
在本文撰写时,Sphinx中包括 MySQL和PostgreSQL数据源的驱动程序,这些驱动使用数据库系统提供的C/C++原生接口连接到数据库服务器并获取数据。此外,Sphinx还提供了额外的被成为xmlpipe的数据源驱动,该驱动运行某个具体的命令,并从该命令的输出中读入数据。数据的格式在 3.8, “xmlpipe数据源” 中有介绍。
如果确有必要,一个索引的数据可以来自多个数据源。这些数据将严格按照配置文件中定义的顺序进行处理。所有从这些数据源获取到的文档将被合并,共同产生一个索引,如同他们来源于同一个数据源一样。
3.2.属性
属性是附加在每个文档上的额外的信息(值),可以在搜索的时候用于过滤和排序。
搜索结果通常不仅仅是进行文档的匹配和相关度的排序,经常还需要根据其他与文档相关联的值,对结果进行额外的处理。例如,用户可能需要对新闻检索结果依次按日期和相关度排序,检索特定价格范围内的产品,检索某些特定用户的">blog日志,或者将检索结果按月分组。为了高效地完成上述工作,Sphinx允许给文档附加一些额外的值,并把这些值存储在全文索引中,以便在对全文匹配结果进行过滤、排序或分组时使用。
论坛帖子表是一个很好的例子。假设只有帖子的标题和内容这两个字段需要全文检索,但是有时检索结果需要被限制在某个特定的作者的帖子或者属于某个子论坛的帖子中(也就是说,只检索在SQL表的author_id和forum_id这两个列上有特定值的那些行),或者需要按 post_date列对匹配的结果排序,或者根据post_date列对帖子按月份分组,并对每组中的帖子计数。
为实现这些功能,可以将上述各列(除了标题和内容列)作为属性做索引,之后即可使用 API调用来设置过滤、排序和分组。以下是一个例子:
示例:sphinx.conf片断:
... sql_query = SELECT id, title, content, \
author_id, forum_id, post_date FROM my_forum_posts sql_attr_uint = author_id sql_attr_uint = forum_id sql_attr_timestamp = post_date ...
示例:应用程序代码 (PHP):
// only search posts by author whose ID is 123 $cl->SetFilter ( "author_id", array ( 123 ) );
// only search posts in sub-forums 1, 3 and 7 $cl->SetFilter ( "forum_id", array ( 1,3,7 ) );
// sort found posts by posting date in descending order $cl->SetSortMode ( SPH_SORT_ATTR_DESC, "post_date" );
可以通过名字来指示特定的属性,并且这个名字是大小写无关的(注意:直到目前为止, Sphinx还不支持中文作为属性的名称)。属性并不会被全文索引,他们只是按原封不动的存储在索引文件中。目前支持的属性类型如下:
?无符号整数(1-32位宽)
? UNIX时间戳(timestamps)
?浮点值(32位,IEEE 754单精度)
?字符串叙述 (尤其是计算出的整数值);
? 多值属性 MVA (multi-value attributes)( 32位无符号整形值的变长序列).
由各个文档的全部的属性信息构成了一个集合,它也被称为文档信息(docinfo),docinfo可以按如下两种方式之一存储:
与全文索引数据分开存储(“外部存储”,在.spa文件中存储) ?
在全文索引数据中,每出现一次文档ID就出现相应的文档信息(“内联存储”,在.spd文件中存储).
当采用外部存储方式时,searchd总是在RAM中保持一份.spa文件的拷贝(该文件包含所有文档的所有文档信息)。这是主要是为了提高性能,因为磁盘的随机访问太慢了。相反,内联存储并不需要任何额外的RAM,但代价是索引文件的体积大大地增加了;请注意,全部属性值在文档ID出现的每一处都被复制了一份,而文档ID出现的次数恰是文档中不同关键字的数目。仅当有一个很小的属性集、庞大的数据集和受限的RAM时,内联存储才是一个可考虑的选择。在大多数情况下,外部存储可令建立索引和检索的效率都大幅提高。
检索时采用外部存储方式产生的的内存需求为 (1+number_of_attrs)*number_of_docs*4字节,也就是说,带有两个属性和一个时间戳的1千万篇文档会消耗(1+2+1)*10M*4 = 160 MB的 RAM。这是每个检索的守护进程(daemon)消耗的量,而不是每次查询,searchd仅在启动时分配160MB的内存,读入数据并在不同的查询之间保持这些数据。子进程并不会对这些数据做额外的拷贝。