SPHINX入门须知的概念

本文介绍如何配置Coreseek全文检索系统,包括数据源配置、属性设置、索引配置等内容,帮助读者理解如何针对具体需求调整配置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

测试文件 http://www.coreseek.cn/uploads/csft/test/documents.sql

在线SPHINX手册:http://www.coreseek.cn/docs/coreseek_3.2-sphinx_0.9.9.html#api-func-query

数据表字段取值对应到Coreseek的索引中,其关系如下:
数据表字段取值对应到Coreseek的索引中,其关系如下: 数据库: SELECT id, group_id, UNIX_TIMESTAMP(date_added) AS date_added, score, title, content FROM documents id      : 自增字段,表的主键,整数 group_id   : 整数字段 date_added : 整数字段,使用UNIX_TIMESTAMP可将datetime类型转换为整数的timestamp score     : 浮点数字段 title     : 字符串字段 content    : 文本字段 业务分析: 文档编号:id 查询过滤:分组(group_id),时间(date_added),score 全文检索:title、content Coreseek索引配置: id          :ID属性,必须提供,在SQL语句中字段名称不限            对应SQL查询的第一个字段,系统自动使用,内部属性名为@id,不需要也不能在配置中设定            使用SetFilter()过滤,或者使用SetIDRange()过滤;            SphinxSE之中,使用filter或者minid, maxid过滤 sql_attr_uint    :整数属性,以上group_id、date_added都可用此设置,使用SetFilter()过滤,            或者使用SetFilterRange()过滤;            SphinxSE之中,使用filter或者range过滤; sql_attr_float    :浮点数属性,以上score可用此设置,使用SetFilterFloatRange()进行范围过滤,            SphinxSE之中,使用range过滤; sql_attr_timestamp :timestamp属性,整数,以上date_added可用此设置,可用SetFilter()过滤            或者使用SetFilterRange()过滤;            SphinxSE之中,使用filter或者range过滤 sql_attr_str2ordinal :字符串序列属性,以上title可用此设置,仅用于根据该字段排序            但是设置后,该属性不可用于过滤,也不会保存实际字符串内容,更不能全文检索            搜索结果中,其对应的信息为整数,由系统计算出来的排序序列值 全文检索字段    :全文检索字段,以上title、content等字符串或者文本的字段 都可用此设置            任何出现在SQL语句中,既不是ID属性也没有 使用“sql_attr_类型”设置的字段,都是全文字段           使用Query()搜索;            SphinxSE之中,使用query的查询文本进行搜索


简单的数据源配置:mysql数据源配置

#源定义 source mysql { type = mysql #表示使用mysql数据源 sql_host = localhost #表示数据库服务器的链接地址 sql_user = root #表示数据库的用户名 sql_pass = 123456 #表示数据库的密码 sql_db = test #表示数据库的名称 sql_port = 3306 #表示数据库的端口 sql_query_pre = SET NAMES utf8 #从数据库之中读取数据的SQL语句设置 sql_query = SELECT id, group_id, UNIX_TIMESTAMP(date_added) AS date_added, title, content FROM documents #sql_query第一列id 需为整数,且被系统使用,无需再设置sql_attr_uint #使用sql_attr设置的字段,只能作为属性,使用SphinxClient::SetFilter()进行过滤;未被设置的字段,自动作为全文检索的字段,
使用SphinxClient::Query("搜索字符串")进行全文搜索; #title、content作为字符串/文本字段,被全文索引
#从SQL读取到的值必须为整数;sql_attr_uint表示该字段是数值属性 sql_attr_uint = group_id
#从SQL读取到的值必须为整数,作为时间属性;sql_attr_timestamp表示该字段是时间属性;可以不用该配置 sql_attr_timestamp = date_added #命令行查询时,设置正确的字符集,3.2.14开始支持 sql_query_info_pre = SET NAMES utf8
#命令行查询时,从数据库读取原始数据信息 sql_query_info = SELECT * FROM documents WHERE id=$id }

 


 #index定义 index mysql { source = mysql #对应的source名称 path = var/data/mysql #索引存放的位置,路径为var/data docinfo = extern mlock = 0 morphology = none min_word_len = 1 html_strip = 0 #charset_dictpath = /usr/local/mmseg3/etc/ #BSD、Linux环境下设置,/符号结尾 charset_dictpath = etc/ #Windows环境下设置,/符号结尾 charset_type = zh_cn.utf-8 }

3. 建立索引

3.1. 数据源

索引的数据可以来自各种各样不同的来源:SQL数据库、纯文本、HTML文件、邮件等等。从Sphinx/Coreseek的视角看,索引数据是一个结构化的文档 的集合,其中每个文档 是字段的集合,这和SQL数据库的视角有所不同,在那里,每一行代表一个文档,每一列代表一个字段。

如果确有必要,一个索引的数据可以来自多个数据源 。这些数据将严格按照配置文件中定义的顺序进行处理。所有从这些数据源获取到的文档将被合并 ,共同产生一个索引,如同他们来源于同一个数据源一样。

3.2. 属性

属性是 附加在每个文档上的额外的信息(值),可以在搜索的时候用于过滤和排序。

搜索结果通常不仅仅是进行文档的匹配和相关度的排序,经常还需要根据其他与文档相关联的值 ,对结果进行额外的处理。例如,用户可能需要对新闻检索结果依次 按日期和相关度排序,检索特定价格范围内的产品,检索某些特定用户的blog日志,或者将检索结果按月分组。为了高效地完成上述工作,Sphinx允许给 文档附加一些额外的 ,并把这些值存储 在全文索引中,以便在对全文匹配结果进行过滤、排序或分组时使用。

 

全文检索字段

   :全文检索字段,以上title、content等字符串或者文本的字段

都可用此设置
       

   任何出现在SQL语句中,既不是ID属性也没有

使用“sql_attr_类型”设置的字段,都是全文字段       

   使用Query()搜索;
       

   SphinxSE之中,使用query的查询文本进行搜索

属性与全文字段不同,不会被全文索引。他们仅仅是被存储 在索引中,属性进行全文检索式不可能的。如果要对属性进行全文检索,系统将会返回一个错误。

例如,如果column被设置为属性,就不能使用扩展表达式@column 1 去匹配column为1的文档;如果数字字段按照普通的方式被索引,那么就可以这样来匹配。

属性可用于过滤,或者限制返回的数据,以及排序或者 结果分组 ; 也有可能是完全基于属性排序的结果, 而没有任何搜索相关功能的参与.

此外, 属性直接从搜索服务程序返回信息, 而被索引的文本内容则没有返回.

论坛帖子表是一个很好的例子。假设只有帖子的标题和内容这两个字段需要全文检索,但是有时检索结果需要被限制在某个特定的作者的帖子或者属于某个子论坛的 帖子中(也就是说,只检索在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 . 文档信息可以按如下两种方式之一存储:

  •  与全文索引数据分开存储(“外部存储”,在.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。这是每个检索的守护进程(PER DAEMON )消耗的量,而不是每次查询,searchd 仅在启动时分配160MB的内存,读入数据并在不同的查询之间保持这些数据。子进程并不会 对这些数据做额外的拷贝。

3.3. MVA (多值属性)

多值属性MVA (multi-valued attributes)是文档属性的一种重要的特例,MVA使得向文档附加一系列的值作为属性的想法成为可能。这对文章的tags,产品类别等等非常有用。MVA属性支持过滤和分组(但不支持分组排序)。

目前MVA列表项的值被限制为32位无符号整数。列表的长度不受限制,只要有足够的RAM,任意个数的值都可以被附加到文档上(包含MVA值的.spm 文件会被searchd 预缓冲到RAM中)。MVA的源数据来源既可以是一个单独的查询,也可以是文档属性,参考 sql_attr_multi 中的来源类型。在第一种情况中,该查询须返回文档ID和MVA值的序对;而在第二种情况中,该字段被分析为整型值。对于多值属性的输入数据的顺序没有任何限制,在索引过程中这些值会自动按文档ID分组(而相同文档ID下的数据也会排序)。

在过滤过程中,MVA属性中的任何 一个值满足过滤条件,则文档与过滤条 件匹配(因此通过排他性过滤的文档不会包含任何被禁止的值)。按MVA属性分组时,一篇文档会被分到与多个不同MVA值对应的多个组。例如,如果文档集只 包含一篇文档,它有一个叫做tag的MVA属性,该属性的值是5、7和11,那么按tag的分组操作会产生三个组,它们的@count都是 1,@groupby键值分别是5、7和11。还要注意,按MVA分组可能会导致结果集中有重复的文档:因为每篇文文档可能属于不同的组,而且它可能在多 个组中被选为最佳结果,这会导致重复的ID。由于历史原因,PHP API对结果集的行进行按文档ID的有序hash,因此用PHP API进行对MVA属性的分组操作时你还需要使用 SetArrayResult() .

3.4. 索引

为了快速地相应响应查询,Sphinx需要从文本数据中建立一种为查询做优化的特殊的数据结构。这种数据结构被称为索引(index );而建立索引的过程也叫做索引或建立索引(indexing )。

不同的索引类型是为不同的任务设计的。比如,基于磁盘的B-Tree存储结构的索引可以更新起来比较简单(容易向已有的索引插入新的文档),但是搜起来就相当慢。因此Sphinx的程序架构允许轻松实现多种不同的索引类型

目前在Sphinx中实现的唯一一种索引类型是为最优化建立索引和检索的速度而设计的。随之而来的代价是更新索引相当的很慢。理论上讲,更新这种索引甚至可能比从头重建索引还要慢。不过大多数情况下这可以靠建立多个索引来解决索引更新慢的问题,细节请参考 Section 3.11, “实时索引更新” .

实现更多的索引类型支持,已列入计划,其中包括一种可以实时更新的类型。

每个配置文件都可以按需配置足够多的索引。indexer 工具可以将它们同时重新索引(如果使用了--all 选项)或者仅更新明确指出的一个。 searchd 工具会为所有被指明的索引提供检索服务,而客户端可以在运行时指定使用那些索引进行检索。

 

3.5. 源数据的限制

Sphinx/Coreseek索引的源数据有一些限制,其中最重要的一条是:

所有文档的ID必须是唯一的无符号非零整数(根据Sphinx构造时的选项,可能是32位或64位)

如果不满足这个要求,各种糟糕的情况都可能发生。例如,Sphinx/Coreseek建立索引时可能在突然崩溃,或者由于冲突的文档ID而在索引结果中产生奇怪的结果。也可能,一只重达1000磅的大猩猩最后跳出你的电脑,向你扔臭蛋。我告诉过你咯!

3.6. 字符集、大小写转换和转换表

当建立索引时,Sphinx从指定的数据源获得文本文档,将文本分成词的集合,再对每个词做大小写转换,于是“Abc”,“ABC”和“abc”都被当作同一个词(word,或者更学究一点,词项term

为了正确完成上述工作,Sphinx需要知道:

  • 源文本是什么编码的;
  • 那些字符是字母,哪些不是;
  • 哪些字符需要被转换,以及被转换成什么.

这些都可以用 charset_type charset_table 选项为每个索引单独配置. charset_type 指定文档的编码是单字节的(SBCS)还是UTF-8的。在Coreseek中,如果通过charset_dictpath设置中文词典启动了中文分词模式后,则可以使用GBK及BIG5的编码;但是在内部实现中,任然是预先转换成UTF-8编码在进行处理的. charset_table 则指定了字母类字符到它们的大小写转换版本的对应表,没有在这张表中出现的字符被认为是非字母类字符,并且在建立索引和检索时被当作词的分割符来看待。

注意,尽管默认的转换表并不包含空格符 (ASCII code 0x20, Unicode U+0020) , 但是这么做是 完全合法 的. 这在某些情况下可能有用,比如在对tag云构造索引的时候,这样一个用空格分开的词集就可以被当作一个单独的 查询项了.

默认转换表目前包括英文和俄文字符。请您提交您为其他语言撰写的转换表!

在Coreseek中,启用中文分词后,系统会使用MMSeg内置的码表(被硬编码在MMSeg的程序中),因此,charset_table在启用分词后将失效。

3.7. SQL 数据源 (MySQL, PostgreSQL)

对于所有的基于SQL驱动,建立索引的过程如下:

大多数参数是很直观的,例如数据库的用户名、主机、密码。不过,还有一些细节上的问题需要讨论。

区段查询

索引系统需要通过主查询来获取全部的文档信息,一种简单的实现是将整个表的数据读入内存,但是这可能导致整个表被锁定并使得其他操作被阻止(例如:在MyISAM格式上的INSERT操作),同时,将浪费大量内存用于存储查询结果,诸如此类的问题吧。 为了避免出现这种情况,Sphinx/Coreseek支持一种被称为 区段查询 的技术. 首先,Sphinx/Coreseek从数据库中取出文档ID的最小值和最大值,将由最大值和最小值定义自然数区间分成若干份,一次获取数据,建立索引。现举例如下:

Example 1. 区段查询示例:

# in sphinx.conf

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

如果这个表(documents)中,字段ID的最小值和最大值分别是1 和2345,则sql_query将执行3次:

  1. $start 替换为1,并且将 $end 替换为 1000;
  2. $start 替换为1001,并且将 $end 替换为 2000;
  3. $start 替换为2001,并且将 $end 替换为 2345.

显然,这对于只有2000行的表,分区查询与整个读入没有太大区别,但是当表的规模扩大到千万级(特别是对于MyISAM格式的表),分区区段查询将提供一些帮助。

后查询(sql_post) vs. 索引后查询(sql_post_index)

后查询和索引后查询的区别在于,当Sphinx获取到全部文档数据后,立即执行后查询,但是构建索引的过程仍然may 因为某种原因失败。在另一方面,当索引后查询被执行时,可以理所当然的认为 索引已经成功构造完了。因为构造索引可能是个漫长的过程,因此对与数据库的连接在执行后索引操作后被关闭,在执行索引后操作前被再次打开。

 

 

9.1.26. sql_query_info

文档信息查询。 可选选项,默认为空。 仅对 mysql 数据源有效。

仅被命令行搜索所用 ,用来获取和显示文档信息,目前仅对MySQL有效,且仅用于调试目的 。此查询为每个文档ID获取CLI搜索工具要显示的文档信息。 它需要包含$id 宏,以此来对应到查询的文档的ID。







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值