1  /  1  页   1 跳转 查看:3269

sphinx学习笔记

sphinx学习笔记

Sphinx是一个基于SQL的全文检索引擎,可以结合MySQL,PostgreSQL做全文搜索,它可以提供比数据库本身更专业的搜索功能,使得应用程序更容易实现专业化的全文检索。Sphinx特别为一些脚本语言设计搜索API接口,如PHP,Python,Perl,Ruby等,同时为MySQL也设计了一个存储引擎插件。
Sphinx的优良特性


  • 高速索引 (在新款CPU上,近10 MB/秒);
  • 高速搜索 (2-4G的文本量中平均查询速度不到0.1秒);
  • 高可用性 (单CPU上最大可支持100 GB的文本,100M文档);
  • 提供良好的相关性排名
  • 支持分布式搜索;
  • 提供文档摘要生成;
  • 提供从MySQL内部的插件式存储引擎上搜索
  • supports boolean, phrase, and word proximity queries;
  • 支持每个文档多个全文检索域(默认最大32个);
  • 支持每个文档多属性;
  • 支持断词;
  • 支持单字节编码与UTF-8编码;
  • supports English stemming, Russian stemming, and Soundex for morphology;
  • 支持MySQ(MyISAM和InnoDB 表都支持);
  • 支持PostgreSQL.




1.配置文件 sphinx.conf
2.
D:\sphinx\searchd --install --config D:\sphinx\sphinx.conf --servicename EnSphinxSearch
3.
D:\sphinx\indexer  -c D:\sphinx\sphinx.conf --merge b2bsns b2bsnsdelta --merge-dst-range deleted 0 0 --rotate
regsvr32 D:\sphinx\BizSearch.dll
4. 重启 searchd 服务,测试
D:\sphinx\search.exe -c D:\sphinx\sphinx.conf  -i b2bsns -i b2bsnsdelta bu
5.完成程序文件
要点:
--rotate: 该参数可以使我们在不需要停止searchd的情况下,直接加载索引
oSearch.SetMatchMode(4) 支持更丰富的语法查询
sql_query_killlist 次级索引与主索引的配合
 

回复:sphinx学习笔记

Distributed key-value stores present an interesting alternative to some of the functionality relational databases are commonly employed for. Advantages include improved performance, easy replication, horizontal scaling and redundancy.

By nature, key value stores offer one way of retrieving data, by some sort of primary key which uniquely identifies each entry. But what about queries that require more elaborate input in order to collect relevant entries? Full text search engines like Sphinx and Lucence do exactly this and when used in conjunction with a database will query their indexes and return a collection of ids which are then used to retrieve the results from the database. Full text search engines support indexing data sources other than RDBMSs, so there’s no reason why one couldn’t index a distributed key-value store.

distributed-key-value-store-index

Here, we’ll look at how we can integrate Sphinx with MemcacheDB, a distributed key-value store which conforms to the memcached protocol and uses Berkeley DB as its storage back-end.

Sphinx comes with an xmlpipe2 datasource, a generic XML interface aimed at simplifying custom integration. What this means is that our application can transform content from MemcacheDB into this format and feed it to Sphinx for indexing. The highlighted lines from the following Sphinx configuration instruct Sphinx to use the xmlpipe2 source type and invoke the ruby /app/lib/sphinxpipe.rb script in order to retrieve the data to index.

# sphinx.conf

source products_src
{
  type = xmlpipe2
  xmlpipe_command = ruby /app/lib/sphinxpipe.rb
}

index products
{
  source = products_src
  path = /app/sphinx/data/products
  docinfo = extern
  mlock = 0
  morphology = stem_en
  min_word_len = 1
  charset_type = utf-8
  enable_star = 1
  html_strip = 0
}

indexer
{
  mem_limit = 256M
}

searchd
{
  port = 3312
  log = /app/sphinx/log/searchd.log
  query_log = /app/sphinx/log/query.log
  read_timeout = 5
  max_children = 30
  pid_file = /app/sphinx/searchd.pid
  max_matches = 10000
  seamless_rotate = 1
  preopen_indexes = 0
  unlink_old = 1
}

Following is a Product class. Each product instance can present itself as xmlpipe2 data. The class itself gets the entire product catalog as a xmlpipe2 data source. It also has a search method used for querying Sphinx and retrieving matched products from MemcacheDB. Finally, there’s a bootstrap method for populating the store with some example data.

# product.rb

require "rubygems"
require "xml/libxml"
require "memcached"
require "riddle"

class Product
  attr_reader :id
  MEM = Memcached.new('localhost:21201')

  def initialize(id, title)
    @id, @title = id, title
  end

  def to_sphinx_doc
    sphinx_document = XML::Node.new('sphinxocument')
    sphinx_document['id'] = @id
    sphinx_document << title = XML::Node.new('title')
    title << @title
    sphinx_document
  end

  # Query sphinx and load products with matched ids from MemcacheDB
  def self.search(query)
    client = Riddle::Client.new
    client.match_mode = :any
    client.max_matches = 10_000
    results = client.query(query, 'products')
    ids = results[:matches].map {|m| m[oc].to_s}
    MEM.get(ids) if ids.any?
  end

  # Load all products from MemcacheDB and convert them to xmlpipe2 data
  def self.sphinx_datasource
    docset = XML:ocument.new.root = XML::Node.new("sphinxocset")
    docset << sphinx_schema = XML::Node.new("sphinx:schema")
    sphinx_schema << sphinx_field = XML::Node.new('sphinxield')
    sphinx_field['name'] = 'title'

    keys = MEM.get('product_keys')
    products = MEM.get(keys)
    products.each { |id, product| docset << product.to_sphinx_doc }

    %(<?xml version="1.0" encoding="utf-8"?>\n#{docset})
  end

  # Create a some products and store them in MemcacheDB
  def self.bootstrap
    product_ids = ('1'..'5').to_a.inject([]) do |ids, id|
      product = Product.new(id, "product #{id}")
      MEM.set(product.id, product)
      ids << id
    end
    MEM.set('product_keys', product_ids)
  end
end

The sphinxpipe.rb script looks like this.

# sphinxpipe.rb
Product.bootstrap
puts Product.sphinx_datasource

With MemcacheDB (or even memcached for the purpose of this example) running, we can tell Sphinx to create an index of products by invoking indexer --all -c sphinx.conf and then start the search daemon – searchd -c sphinx.conf. Now we’re ready to start querying the index and retrieving results from the distributed store.

puts Product.search('product 1').inspect

It is not uncommon for the database to become a performance hotspot. The integration of a fast, distributed key-value store with an efficient search engine can be an interesting substitute for high throughput data retrieval operations.
 

回复:sphinx学习笔记

使用xml建立sphinx 索引:
3.8. xmlpipe data source

xmlpipe data source was designed to enable users to plug data into Sphinx without having to implement new data sources drivers themselves. It is limited to 2 fixed fields and 2 fixed attributes, and is deprecated in favor of Section 3.9, “xmlpipe2 data source” now. For new streams, use xmlpipe2.

To use xmlpipe, configure the data source in your configuration file as follows:

source example_xmlpipe_source
{
    type = xmlpipe
    xmlpipe_command = perl /www/mysite.com/bin/sphinxpipe.pl
}

The indexer will run the command specified in xmlpipe_command, and then read, parse and index the data it prints to stdout. More formally, it opens a pipe to given command and then reads from that pipe.

indexer will expect one or more documents in custom XML format. Here's the example document stream, consisting of two documents:

Example 2. XMLpipe document stream

<document>
<id>123</id>
<group>45</group>
<timestamp>1132223498</timestamp>
<title>test title</title>
<body>
this is my document body
</body>
</document>

<document>
<id>124</id>
<group>46</group>
<timestamp>1132223498</timestamp>
<title>another test</title>
<body>
this is another document
</body>
</document>


Legacy xmlpipe legacy driver uses a builtin parser which is pretty fast but really strict and does not actually fully support XML. It requires that all the fields must be present, formatted exactly as in this example, and occur exactly in the same order. The only optional field is timestamp; it defaults to 1.
3.9. xmlpipe2 data source

xmlpipe2 lets you pass arbitrary full-text and attribute data to Sphinx in yet another custom XML format. It also allows to specify the schema (ie. the set of fields and attributes) either in the XML stream itself, or in the source settings.

When indexing xmlpipe2 source, indexer runs the given command, opens a pipe to its stdout, and expects well-formed XML stream. Here's sample stream data:

Example 3. xmlpipe2 document stream

<?xml version="1.0" encoding="utf-8"?>
<sphinxocset>

<sphinx:schema>
<sphinxield name="subject"/>
<sphinxield name="content"/>
<sphinx:attr name="published" type="timestamp"/>
<sphinx:attr name="author_id" type="int" bits="16" default="1"/>
</sphinx:schema>

<sphinxocument 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>
</sphinxocument>

<!-- ... more documents here ... -->

</sphinxocset>


Arbitrary fields and attributes are allowed. They also can occur in the stream in arbitrary order within each document; the order is ignored. There is a restriction on maximum field length; fields longer than 2 MB will be truncated to 2 MB (this limit can be changed in the source).

The schema, ie. complete fields and attributes list, must be declared before any document could be parsed. This can be done either in the configuration file using xmlpipe_field and xmlpipe_attr_XXX settings, or right in the stream using <sphinx:schema> element. <sphinx:schema> is optional. It is only allowed to occur as the very first sub-element in <sphinxocset>. If there is no in-stream schema definition, settings from the configuration file will be used. Otherwise, stream settings take precedence.

Unknown tags (which were not declared neither as fields nor as attributes) will be ignored with a warning. In the example above, <misc> will be ignored. All embedded tags and their attributes (such as <b> in <subject> in the example above) will be silently ignored.

Support for incoming stream encodings depends on whether iconv is installed on the system. xmlpipe2 is parsed using libexpat parser that understands US-ASCII, ISO-8859-1, UTF-8 and a few UTF-16 variants natively. Sphinx configure script will also check for libiconv presence, and utilize it to handle other encodings. libexpat also enforces the requirement to use UTF-8 charset on Sphinx side, because the parsed data it returns is always in UTF-8.

XML elements (tags) recognized by xmlpipe2 (and their attributes where applicable) are:

sphinx:docset
    Mandatory top-level element, denotes and contains xmlpipe2 document set.
sphinx:schema
    Optional element, must either occur as the very first child of sphinx:docset, or never occur at all. Declares the document schema. Contains field and attribute declarations. If present, overrides per-source settings from the configuration file.
sphinxield
    Optional element, child of sphinx:schema. Declares a full-text field. The only recognized attribute is "name", it specifies the element name that should be treated as a full-text field in the subsequent documents.
sphinx:attr
    Optional element, child of sphinx:schema. Declares an attribute. Known attributes are:

        * "name", specifies the element name that should be treated as an attribute in the subsequent documents.
        * "type", specifies the attribute type. Possible values are "int", "timestamp", "str2ordinal", "bool", and "float".
        * "bits", specifies the bit size for "int" attribute type. Valid values are 1 to 32.
        * "default", specifies the default value for this attribute that should be used if the attribute's element is not present in the document.

sphinx:document
    Mandatory element, must be a child of sphinx:docset. Contains arbitrary other elements with field and attribute values to be indexed, as declared either using sphinxield and sphinx:attr elements or in the configuration file. The only known attribute is "id" that must contain the unique integer document ID.
 

回复:sphinx学习笔记

Coreseek 全文检索服务器 2.0 (Sphinx 0.9.8)参考手册
文档版本:
v0.9
目录
1.
简介
1.1.
什么是
Sphinx
1.2. Sphinx
的特性
1.3.
如何获得
Sphinx
1.4.
许可协议
1.5.
作者和贡献者
1.6.
开发历史
2.
安装
2.1.
支持的操作系统
2.2.
依赖的工具
2.3.
安装
Sphinx
2.4.
已知的问题和解决方法
2.5. Sphinx
快速入门教程
3.
建立索引
3.1.
数据源
3.2.
属性
3.3.
多值属性
( MVA

multi-valued attributes)
3.4.
索引
3.5.
数据源的限制
3.6.
字符集
, 大小写转换
, 和转换表
3.7. SQL
数据源
(MySQL, PostgreSQL)
3.8. xmlpipe
数据源
3.9. xmlpipe2
数据源
3.10.
实时索引
更新
3.11.
索引合并
4.
搜索
4.1.
匹配模式
4.2.
布尔查询
4.3.
扩展查询
4.4.
权值计算
4.5.
排序模式
4.6.
结果分组(聚类)
4.7.
分布式搜索
4.8.
searchd
日志格式
5. API
参考
5.1.
通用
API
方法
5.1.1. GetLastError
5.1.2. GetLastWarning
5.1.3. SetServer
5.1.4. SetRetries
5.1.5. SetArrayResult
5.2.
通用搜索设置
5.2.1. SetLimits
5.2.2. SetMaxQueryTime
5.3.
全文搜索设置
5.3.1. SetMatchMode
5.3.2. SetRankingMode
5.3.3. SetSortMode
5.3.4. SetWeights
5.3.5. SetFieldWeights
5.3.6. SetIndexWeights
5.4.
结果集过滤设置
5.4.1. SetIDRange
5.4.2. SetFilter
5.4.3. SetFilterRange
5.4.4. SetFilterFloatRange
5.4.5. SetGeoAnchor
5.5. GROUP BY
设置
5.5.1. SetGroupBy
5.5.2. SetGroupDistinct
5.6.
搜索
5.6.1. Query
5.6.2. AddQuery
5.6.3. RunQueries
5.6.4. ResetFilters
5.6.5. ResetGroupBy
5.7.
额外的方法
5.7.1. BuildExcerpts
5.7.2. UpdateAttributes
6. MySQL
存储引擎
(SphinxSE)
6.1. SphinxSE
概览
6.2.
安装
SphinxSE
6.2.1.

MySQL 5.0.x

编译
SphinxSE
6.2.2.

MySQL 5.1.x
上编译
SphinxSE
6.2.3. SphinxSE
安装测试
6.3.
使用
SphinxSE
7.
报告
bugs
8.
sphinx.conf
选项参考
8.1. Data source
配置选项
8.1.1. type
8.1.2. sql_host
8.1.3. sql_port
8.1.4. sql_user
8.1.5. sql_pass
8.1.6. sql_db
8.1.7. sql_sock
8.1.8. mysql_connect_flags
8.1.9. sql_query_pre
8.1.10. sql_query
8.1.11. sql_query_range
8.1.12. sql_range_step
8.1.13. sql_attr_uint
8.1.14. sql_attr_bool
8.1.15. sql_attr_timestamp
8.1.16. sql_attr_str2ordinal
8.1.17. sql_attr_float
8.1.18. sql_attr_multi
8.1.19. sql_query_post
8.1.20. sql_query_post_index
8.1.21. sql_ranged_throttle
8.1.22. sql_query_info
8.1.23. xmlpipe_command
8.1.24. xmlpipe_field
8.1.25. xmlpipe_attr_uint
8.1.26. xmlpipe_attr_bool
8.1.27. xmlpipe_attr_timestamp
8.1.28. xmlpipe_attr_str2ordinal
8.1.29. xmlpipe_attr_float
8.1.30. xmlpipe_attr_multi
8.2.
索引配置选项
8.2.1. type
8.2.2. source
8.2.3. path
8.2.4. docinfo
8.2.5. mlock
8.2.6. morphology
8.2.7. stopwords
8.2.8. wordforms
8.2.9. exceptions
8.2.10. min_word_len
8.2.11. charset_type
8.2.12. charset_table
8.2.13. ignore_chars
8.2.14. min_prefix_len
8.2.15. min_infix_len
8.2.16. prefix_fields
8.2.17. infix_fields
8.2.18. enable_star
8.2.19. ngram_len
8.2.20. ngram_chars
8.2.21. phrase_boundary
8.2.22. phrase_boundary_step
8.2.23. html_strip
8.2.24. html_index_attrs
8.2.25. html_remove_elements
8.2.26. local
8.2.27. agent
8.2.28. agent_connect_timeout
8.2.29. agent_query_timeout
8.2.30. preopen
8.2.31. charset_dictpath
8.3.
indexer
程序配置选项
8.3.1. mem_limit
8.3.2. max_iops
8.3.3. max_iosize
8.4.
searchd
程序配置选项
8.4.1. address
8.4.2. port
8.4.3. log
8.4.4. query_log
8.4.5. read_timeout
8.4.6. max_children
8.4.7. pid_file
8.4.8. max_matches
8.4.9. seamless_rotate
8.4.10. preopen_indexes
8.4.11. unlink_old
1. 简介
1.1.
什么是 Sphinx
Sphinx 是一个在 GPLv2 下发布的一个全文检索引擎,商业授权(例如, 嵌入到其他程序中)
需要联系我们(
Sphinxsearch.com)以获得商业授权。
一般而言,
Sphinx 是一个独立的搜索引擎,意图为其他应用提供高速、低空间占用、高结果
相关度的全文搜索功能。
Sphinx 可以非常容易的与 SQL 数据库和脚本语言集成。
当前系统内置
MySQL 和 PostgreSQL 数据库数据源的支持,也支持从标准输入读取特定格式

XML 数据。通过修改源代码,用户可以自行增加新的数据源(例如:其他类型的 DBMS
的原生支持)。
搜索
API 支持 PHP、Python、Perl、Rudy 和 Java,并且也可以用作 MySQL 存储引擎。搜索
API 非常简单,可以在若干个小时之内移植到新的语言上。
Sphinx 是 SQL Phrase Index 的缩写,但不幸的和 CMU 的 Sphinx 项目重名。
Coreseek 全文检索服务器 2.0 是在 Sphinx 基础上开发的全文检索软件,按照 GPLv2 协议发行。
Coreseek (
http://www.coreseek.com
) 为 sphinx 在中国地区的用户提供支持服务,如果您不希望
纠缠与琐碎的技术细节,请直接联系我。
本文可能存在潜在的翻译错误,如果您发现本文的翻译错误,请联系我:
我的联系方式:
coreseek@gmail.com
李沫南
1.2. Sphinx
的特性

高速的建立索引
(在当代 CPU 上,峰值性能可达到 10 MB/秒);

高性能的搜索
(在 2 – 4GB 的文本数据上,平均每次检索响应时间小于 0.1 秒);

可处理海量数据
(目前已知可以处理超过 100 GB 的文本数据, 在单一 CPU 的系统上可
处理
100 M 文档);

提供了优秀的相关度算法,基于短语相似度和统计(
BM25)的复合 Ranking 方法;

支持分布式搜索
;

provides document exceprts generation;

可作为
MySQL 的存储引擎提供搜索服务;

支持布尔、短语、词语相似度等多种检索模式
;

文档支持多个全文检索字段
(最大不超过 32 个);

文档支持多个额外的属性信息
(例如:分组信息,时间戳等);

停止词查询
;

支持单一字节编码和
UTF-8 编码;

原生的
MySQL 支持(同时支持 MyISAM 和 InnoDB );

原生的
PostgreSQL 支持.
1.3.
如何获得 Sphinx
Sphinx 可以从官方网站
http://www.sphinxsearch.com/
下载,支持中文分词的
Sphinx 可以从
http://www.coreseek.com/ 下载。
目前,
Sphinx 的发布包包括如下软件:

indexer: 用于创建全文索引;

search: 一个简单的命令行(CLI) 的测试程序,用于测试全文索引;

searchd: 一个守护进程,其他软件可以通过这个守护进程进行全文检索;

sphinxapi: 一系列 searchd 的客户端 API 库,用于流行的 Web 脚本开发语言(PHP,
Python, Perl, Ruby)。
1.4.
许可 协议
This program is free software; you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version. See COPYING file for details.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if
not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA
If you don't want to be bound by GNU GPL terms (for instance, if you would like to embed Sphinx
in your software, but would not like to disclose its source code), please contact
the author
to obtain
a commercial license.
1.5. 作者和贡献者
作者
Sphinx 的最初作者和目前的主要开发人员:

Andrew Aksyonoff, <
shodan(at)shodan.ru
>
贡献者

Sphinx 的开发出过力的人员和他们的贡献如下(以下排名不分先后):

Robert "coredev" Bengtsson (Sweden), initial version of PostgreSQL data source;

Len Kranendonk, Perl API

Dmytro Shteflyuk, Ruby API
此外,还有许多人提出了宝贵的想法、错误报告以及修正。在此一并致谢。
1.6.
历史
Sphinx 的开发工作可以上溯到 2001 年,当时作者试图为一个数据库驱动的网站寻找一个可
接受的搜索的解决方案,但是当时没有任何方案能够满足要求。事实上,主要是如下问题:

搜索质量
(例如:有效的相关度算法)

单纯的统计学方法的效果非常糟糕,特别是在大量的短篇文档的集合上,例如:
论坛、博客等等。

搜索速度

特别是当搜索的短语包括“停止词”时,表现的尤其明显,例如:
"to be or not
to be"

建立索引时,可控的磁盘和
CPU 消耗

在虚拟主机的环境下,这一点的重要性要超过对索引构造速度的要求
年复一年,其他的解决方案有了很多改进,但是,我个人认为仍然没有一种解决方案足够的
好,能让我将搜索平台迁移过去。
去年,
Sphinx 的用户给了我很多正面的反馈,因此,显而易见的,Sphinx 的开发过程将会继
续(也许将持续到世界末日)。
2. 安装
2.1. 支持的操作系统
在绝大多数现代的
Unix 类操作系统上,只需要一个 C++编译器就可以编译并运行 Sphinx,
而不需要对源码进行任何改动。
目前,
Sphinx 可以在以下系统上运行:

Linux 2.4.x, 2.6.x (包括各种发行版)

Windows 2000, XP

FreeBSD 4.x, 5.x, 6.x

NetBSD 1.6, 3.0

Solaris 9, 11

Mac OS X
支持的
CPU 种类包括 X86, X86-64, SPARC64。
我希望
Sphinx 也能够在其他的 Unix 平台上工作,如果你运行 Sphinx 使用的操作系统不在上
面的名单中,请告诉我。
目前的阶段,
Sphinx 的 Windows 版可用于测试和调试,但不建议用于生产系统。最突出的
两个问题是:
1)缺少并发查询的支持;2)缺少索引数据热切换的支持。虽然目前已经有成
功的生产环境克服了这两个问题,仍然不推荐在
Windows 下运行 Sphinx 提供高强度的搜索
服务。
2.2. 依赖的工具

UNIX 平台上,你需要以下的工具用来编译和安装 Sphinx:

C++编译器。GNU gcc 就能够干这个活。

make 程序。GNU make 就能够干这个活。

Windows 平台上,你需要 Microsoft Visual C/C++ Studio .NET 2003 or 2005。其他的编译器
/开发环境也许也能搞定这件事,但你可能需要自己手工制作他们所需的 Makefile 或者工程
文件。
2.3.
安装 Sphinx
1. 将你下载的 tar 包解压,并进入 sphinx 子目录:
$ tar xzvf sphinx-0.9.7.tar.gz
$ cd sphinx
2. 运行 configuration 程序:
$ ./configure
configure 程序有很多运行选项。完整的列表可以通过使用 --help 开关得到。最重
要的如下:

--prefix, 定义将 Sphinx 安装到何处;

--with-mysql, 当自动检测失败时,指出在那里能找到 MySQL 头文件和库
文件
;

--with-pgsql, 指出在那里能找到 PostgreSQL 头文件和库文件。
3. 制作二进制程序:
$ make
4. 按照二进制程序到你选好的目录下:
$ make install
2.4. 已知的问题和解决方法
如果 configure 程序没有找到 MySQL 的头文件和库文件,请试图检查 mysql-devel 这
个包是否安装了。在有些系统上,默认安装包括这个包。
如果
make 程序给出如下错误提示,
/bin/sh: g++: command not found
make[1]: *** [libsphinx_a-sphinx.o] Error 127
请检查 gcc-c++ 这个包是否安装了。
如果你在编译时得到如下错误
sphinx.cpp:67: error: invalid application of `sizeof' to
incomplete type `Private::SizeError<false>'
这意味着某些编译时的类型检查失败了,一个最有可能的原因是在你的系统上类型
off_t 的
长度小于
64bit。一个快速的修复手段是,你可以修改 sphinx.h ,将在定义类型 SphOffset_t
处,将
off_t 替换成 DWORD,需要注意,这种改动将使你的全文索引文件不能超过 2GB。
即便这种修改有用,也请汇报这一问题,在汇报中请包括具体的错误信息以及操作系统编译
器的配置情况。这样,我可能能够在下一个版本中解决这一问题。
如何你遇到了其他的任何问题,或者前面的建议对你没有帮助,别犹豫,请立刻联系我。
2.5. Sphinx 快速入门教程
以下所有的例子都假设你将
sphinx 安装在目录 /usr/local/sphinx 中了。
为了使用
Sphinx,你需要:
1. 创建配置文件
缺省的配置文件名为 sphinx.conf。全部的 Sphinx 提供的程序默认都在当前工作
的目录下寻找该文件。
由 configure 程序生成的示例配置文件 sphinx.conf.dist 中包括全部选项的
注释,复制并编辑这个文件使之适用于你的具体情况:
$ cd /usr/local/sphinx/etc
$ cp sphinx.conf.dist sphinx.conf
$ vi sphinx.conf
在示例配置文件中,将试图对
MySQL 数据库 test 中的 documents 表建立索引;
因此在这里还提供了 example.sql 用于给测试表增加数据用于测试:
$ mysql -u test < /usr/local/sphinx/etc/example.sql
2. 运行 indexer 创建你的全文索引:
$ cd /usr/local/sphinx/etc
$ /usr/local/sphinx/bin/indexer
3. 检索你新创建的索引!
你可以使用
search 实用程序可以从命令行对索引进行检索:
$ cd /usr/local/sphinx/etc
$ /usr/local/sphinx/bin/search test
如果要从
PHP 脚本检索索引,你需要:
1. 运行守护进程 searchd,PHP 脚本需要连接到 searchd 上进行检索 :
$ cd /usr/local/sphinx/etc
$ /usr/local/sphinx/bin/searchd
2. 运行 PHP API 附带的 test 脚本(运行之前请确认 searchd 守护进程已启动):
$ cd sphinx/api
$ php test.php test
3. 将 API 文件(位于 api/sphinxapi.php) 包含进你自己的脚本,开始编程。
搜索愉快!
3. 建立索引
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 的内存,读入数据并在不同的查询之间保持这些数据。子进程并不会对这些
数据做额外的拷贝。
3.3.
多值属性 MVA (multi-valued attributes)
多值属性
MVA (multi-valued attributes)是文档属性的一种重要的特例,MVA 使得向文档附加
一系列的值作为属性的想法成为可能。这对文章的
tags,产品类别等等非常有用。MVA 属
性支持过滤和分组(但不支持分组排序)。
目前
MVA 列表项的值被限制为 32 位无符号整数。列表的长度不受限制,只要有足够的
RAM,任意个数的值都可以被附加到文档上(包含 MVA 值的.spm 文件会被 searchd 预缓冲

RAM 中)。源数据既可以来自一个单独的查询,也可以来自文档属性,参考
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 中实现的唯一一种索引类型是为最优化建立索引和检索的速度而设计的。随
之而来的代价是更新索引相当的很慢。理论上讲,更新这种索引甚至可能比从头重建索引还
要慢。不过大多数情况下这可以靠建立多个索引来解决索引更新慢的问题,细节请参考

3.10, “
实时索引更新

实现更多的索引类型支持,已列入计划,其中包括一种可以实时更新的类型。
每个配置文件都可以按需配置足够多的索引。indexer 工具可以将它们同时重新索引
(如果使用了--all 选项)或者仅更新明确指出的一个。 Searchd 工具会为所有被指明
的索引提供检索服务,而客户端可以在运行时指定使用那些索引进行检索。
3.5
源数据的限制
Sphinx 索引的源数据有一些限制,其中最重要的一条是:
所有文档的
ID 必须是唯一的无符号非零整数(根据 Sphinx 构造时的选项,可能是 32 位或
64 位)
如果不满足这个要求,各种糟糕的情况都可能发生。例如,
Sphinx 建立索引时可能在突然崩
溃,或者由于冲突的文档
ID 而在索引结果中产生奇怪的结果。也可能,一只重达 1000 磅的
大猩猩最后跳出你的电脑,向你扔木桶。我告诉你咯!
3.6 字符集、大小写转换和转换表
当建立索引时,
Sphinx 从指定的数据源获得文本文档,将文本分成词的集合,再对每个词做
大小写转换,于是“
Abc”,“ABC”和“abc”都被当作同一个词(word,或者更学究一点,
词项
term)
为了正确完成上述工作,
Sphinx 需要知道:

源文本是什么编码的

那些字符是字母,哪些不是

哪些字符需要被转换,以及被转换成什么
这些都可以用
charset_type

charset_table
选项为每个索引单独配置。
charset_type
指定文档的编码是单字节的(SBCS)还是 UTF-8 的(注意:Sphinx 目前只
支持这两种编码,
GBK 及 BIG5 的编码需要预先转成 UTF-8 的)。
charset_table
则指定
了字母类字符到它们的大小写转换版本的对应表,没有在这张表中出现的字符被认为是非字
母类字符,并且在建立索引和检索时被当作词的分割符来看待。
注意,尽管默认的转换表并不包含空格符 (
ASCII 0x20, Unicode U+0020),但这么做是完
全合法的。这在某些情况下可能有用,比如在对
tag 云构造索引的时候,这样一个用空格分
开的词集就可以被当作一个单独的查询项了。
默认转换表目前包括英文和俄文字符。请您提交您为其他语言撰写的转换表!
3.7. SQL
数据源 (MySQL, PostgreSQL)
对于所有的
SQL 驱动,建立索引的过程如下:

连接到数据库

执行预查询
(参见

8.1.9, “sql_query_pre”
) ,以便完成所有必须的初始设置,比如

MySQL 连接设置编码

执行主查询(参见

8.1.10, “sql_query”
),其返回的的数据将被索引

执行后查询
(参见

8.1.19, “sql_query_post”
),以便完成所有必须的清理工作

关闭到数据库的连接

对短语进行排序
(或者学究一点, 索引类型相关的后处理)

再次建立到数据库的连接

执行后索引查询
(参见

8.1.20, “sql_query_post_index”
) ,以便完成所有最终的清理
工作

再次关闭到数据库的连接
大多数参数是很直观的,例如数据库的用户名、主机、密码。不过,还有一些细节上的问题
需要讨论。
分区查询
Sphinx 需要通过主查询来获取全部的文档信息,一种简单的实现是将整个表的数据读入内存,
但是这可能导致整个表被锁定并使得其他操作被阻止(例如:在
MyISAM 格式上的 INSERT
操作),同时,将浪费大量内存用于存储查询结果,诸如此类的问题吧。为了避免出现这种
情况,
Sphinx 支持一种被称作“分区查询”的技术。首先,Sphinx 从数据库中取出文档 ID
的最小值和最大值,将由最大值和最小值定义自然数区间分成若干份,一次获取数据,建立
索引。现举例如下:

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 替换为 2000 ,并且将 $end 替换为 2345.
显然,这对于只有
2000 行的表,分区查询与整个读入没有太大区别,但是当表的规模扩大
到千万级(特别是对于
MyISAM 格式的表),分区查询将提供一些帮助。
后查询(sql_post) vs. 索引后查询(sql_post_index)
后查询和索引后查询的区别在于,当
Sphinx 获取到全部文档数据后,立即执行后查询,但
是构建索引的过程仍然可能因为某种原因失败。在另一方面,当索引后查询被执行时,可以
理所当然的认为索引已经成功构造完了。因为构造索引可能是个漫长的过程,因此对与数据
库的连接在执行后索引操作后被关闭,在执行索引后操作前被再次打开。
3.8. xmlpipe
数据源
xmlpipe 数据源是处于让用户能够将现有数据嵌入 Sphinx 而无需开发新的数据源驱动的目的
被设计和提供的。它将每篇文档限制为只能包括两个可全文索引的字段,以及只能包括两个
属性。
xmlpipe 数据源已经被废弃,在

3.9, “xmlpipe2
数据源”
中描述了
xmlpipe 的替代

xmlpipe2 数据源。对于新的数据,建议采用 xmlpipe2。.
为了使用
xmlpipe,需要将配置文件改为类似如下的样子:
source example_xmlpipe_source
{
type = xmlpipe
xmlpipe_command = perl /www/mysite.com/bin/sphinxpipe.pl
}
indexer 实用程序将要运行
xmlpipe_command
所指定的命令,而后读取其向标准输出上
输出的数据,并对之进行解析并建立索引。严格的说,是
Sphinx 打开了一个与指定命令相
连的管道,并从这个管道读取数据。
indexer 实用程序假定在从标准输入读入的 XML 格式的数据中中存在一个或更多的文档。下
面是一个包括两个文档的文档数据流的例子:
Example 2. XMLpipe 文档数据流
<document>
<id>123</id>
<group>45</group>
<timestamp>1132223498</timestamp>
<title>test title</title>
<body>
this is my document body
</body>
</document>
<document>
<id>124</id>
<group>46</group>
<timestamp>1132223498</timestamp>
<title>another test</title>
<body>
this is another document
</body>
</document>
遗留的
xmlpipe 的遗留的数据驱动使用内置的解析器来解析 xml 文档,这个解析器的速度非
常快,但是并没有提供对
XML 格式完整支持。这个解析器需要文档中包括全部的字段,并
且严格按照例子中给出的格式给出,而且字段的出现顺序需要严格按照例子中给出的顺序。
仅有一个字段
timestamp 是可选的,它的缺省值为 1。
3.9. xmlpipe2
数据源
xmlpipe2 使你可以用另一种自定义的 XML 格式向 Sphinx 传输任意文本数据和属性数据。数
据模式(即数据字段的集合或者属性集)可以由
XML 流本身指定,也可以在配置文件中数
据源的配置部分中指定。
Xmlpipe2
在对
xmlpipe2 数据源做索引时,索引器运行指定的命令,打开一个连接前述命令标准输出
的管道,并等待接受具有正确格式的
XML 数据流。以下是一个数据流的样本:
示例
3 xmlpipe2 文档流
<?xml version="1.0" encoding="utf-8"?>
<sphinxocset>
<sphinx:schema>
<sphinxield name="subject"/>
<sphinxield name="content"/>
<sphinx:attr name="published" type="timestamp"/>
<sphinx:attr name="author_id" type="int" bits="16" default="1"/>
</sphinx:schema>
<sphinxocument 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>
</sphinxocument>
<!-- ... more documents here ... -->
</sphinxocset>
任意多的数据字段和属性都是允许的。数据字段和属性在同一文档元素中出现的先后顺序没
有特别要求。。单一字段数据的最大长度有限制,超过
2MB 的数据会被截短到 2MB(但这
个限制可以在配置文件中数据源部分修改)
数据模式,即数据字段和属性的完整列表,必须在任何文档被分析之前就确定。这既可以在
配置文件中用
xmlpipe_field 和 xmlpipe_attr_xxx 选项指定,也可以就在数据流中用
<sphinx:schema>元素指定。 <sphinx:schema>元素是可选的,但如果出现,就必须是
<sphinxocset>元素的第一个子元素。如果没有在数据流中内嵌的数据模式定义,配置文件
中的相关设置就会生效,否则数据流内嵌的设置被优先采用。
未知类型的标签(既不是数据字段,也不是属性的标签)会被忽略,但会给出警告。在上面
的例子中,
<misc>标签会被忽略。所有嵌入在其他标签中的标签及其属性都会被无视(例如
上述例子中嵌入在
<subject>标签中的<b>标签)
支持输入数据流的何种字符编码取决于系统中是否安装了
iconv。xmlpipe2 是用 libexpat 解析
器解析的,该解析器内置对
US-ASCII,ISO-8859-1,UTF-8 和一些 UTF-16 变体的支持。
Sphinx 的 configure 脚本也会检查 libiconv 是否存在并使用它来处理其他的字符编码。
libexpat 也隐含的要求在 Sphinx 端使用 UTF-8,因为它返回的分析过的数据总是 UTF-8 的。
xmlpipe2 可以识别的 XML 元素(标签)(以及前述元素可用的属性)如下:
sphinx:docset
顶级元素,用于标明并包括
xmlpipe2 文档。
Sphinx:schema
可选元素,它要么是
sphinx:docset 的第一个子元素,要么干脆不出现。声明文档的模
式。包括数据字段和属性的声明。若此元素出现,则它会覆盖配置文件中对数据源的
设定。

Sphinxield
可选元素,
sphinx:schema 的子元素。声明一个全文数据字段。唯一可识别的属性是

name”,它指定了字段的名称,后续数据文档中具有此名称的元素的数据都被当作待
检索的全文数据对待。
sphinx:attr
可选元素,
sphinx:schema 的子元素。用于声明具体属性。其已知的属性有:


name”,设定该属性名称,后续文档中具有该名称的元素应被当作一个属性
对待。


type”,设定该属性的类型。可能的类型包括

int”,“timestamp”,“str2ordinal”,“bool”和“float”


bits”,设定“int”型属性的宽度,有效值为 1 到 32


default”,设定该属性的默认值,若后续文档中没有指定这个属性,则使用此
默认值。
Sphinx:document
必须出现的元素,必须是
sphinx:docset 的子元素。包含任意多的其他元素,这些子元
素带有待索引的数据字段和属性值,而这些数据字段或属性值既可以是用
sphinxield

sphinx:attr 元素声明的,也可以在配置文件中声明。唯一的已知属性是“id”,它必
须包含一个唯一的整型的文档
ID。
3.10.
实时索引更新
有这么一种常见的情况:整个数据集非常大,以至于难于经常性的重建索引,但是每次新增
的记录却相当地少。一个典型的例子是:一个论坛有
1000000 个已经归档的帖子,但每天只

1000 个新帖子。
在这种情况下可以用所谓的“主索引+增量索引”(
main+delta)模式来实现“近实时”的
索引更新。
这种方法的基本思路是设置两个数据源和两个索引,对很少更新或根本不更新的数据建立主
索引,而对新增文档建立增量索引。在上述例子中,那
1000000 个已经归档的帖子放在主索
引中,而每天新增的
1000 个帖子则放在增量索引中。增量索引更新的频率可以非常快,而
文档可以在出现几分种内就可以被检索到。
确定具体某一文档的分属那个索引的分类工作可以自动完成。一个可选的方案是,建立一个
计数表,记录将文档集分成两部分的那个文档
ID,而每次重新构建主索引时,这个表都会
被更新。
示例
4 全自动的即时更新
# in MySQL
CREATE TABLE sph_counter
(
counter_id INTEGER PRIMARY KEY NOT NULL,
max_doc_id INTEGER NOT NULL
);
# in sphinx.conf
source main
{
# ...
sql_query_pre = REPLACE INTO sph_counter SELECT 1, MAX(id) FROM documents
sql_query = SELECT id, title, body FROM documents \
WHERE id<=( SELECT max_doc_id FROM sph_counter WHERE counter_id=1 )
}
source delta : main
{
sql_query_pre =
sql_query = SELECT id, title, body FROM documents \
WHERE id>( SELECT max_doc_id FROM sph_counter WHERE counter_id=1 )
}
index main
{
source = main
path = /path/to/main
# ... all the other settings
}
# note how all other settings are copied from main,
# but source and path are overridden (they MUST be)
index delta : main
{
source = delta
path = /path/to/delta
}
3.11. 索引合并
合并两个已有的索引比重新对所有数据做索引更有效率,而且有时候必须这样做(例如在“
主索引+增量索引”分区模式中应合并主索引和增量索引,而不是简单地重新索引“主索引
对应的数据)。因此
indexer 有这个选项。合并索引一般比重新索引快,但在大型索引上仍
然不是一蹴而就。基本上,待合并的两个索引都会被读入内存一次,而合并后的内容需要写
入磁盘一次。例如,合并
100GB 和 1GB 的两个索引将导致 202GB 的 IO 操作(但很可能还
是比重新索引少)
基本的命令语法如下:
indexer --merge DSTINDEX SRCINDEX [--rotate]
SRCINDEX 的内容被合并到 DSTINDEX 中,因此只有 DSTINDEX 索引会被改变。若
DSTINDEX 已经被 searchd 用于提供服务,则--rotate 参数是必须的。最初设计的使用模式是,
将小量的更新从
SRCINDEX 合并到 DSTINDEX 中。因此,当属性被合并时,一旦出现了重
复的文档
ID,SRCINDEX 中的属性值更优先(会覆盖 DSTINDEX 中的值)。不过要注意,
“旧的”关键字并不会被自动删除。例如,在
DSTINDEX 中有一个叫做“old”的关键字与文

123 相关联,而在 SRCINDEX 中则有关键字“new”与同一个文档相关,那么在合并后用
这两个关键字都能找到文档
123。您可以给出一个显式条件来将文档从 DSTINDEX 中移除,
以便应对这种情况,相关的开关是
--merge-dst-range:
indexer --merge main delta --merge-dst-range deleted 0 0
这个开关允许您在合并过程中对目标索引实施过滤。过滤器可以有多个,只有满足全部过滤
条件的文档才会在最终合并后的索引中出现。在上述例子中,过滤器只允许“
deleted”为 0
的那些条件通过,而去除所有标记为已删除(“
deleted”)的记录(可以通过调用
UpdateAttributes()
设置文档的属性)。
4. 搜索
4.1.
匹配模式
有如下可选的匹配模式:

SPH_MATCH_ALL, 匹配所有查询词(默认模式)

SPH_MATCH_ANY, 匹配查询词中的任意一个

SPH_MATCH_PHRASE, 将整个查询看作一个词组,要求按顺序完整匹配

SPH_MATCH_BOOLEAN, 将查询看作一个布尔表达式 (参见

4.2, “
布尔查询语



SPH_MATCH_EXTENDED, 将查询看作一个 Sphinx 内部查询语言的表达式(参见

4.3, “
扩展的查询语法


还有一个特殊的“完整扫描”模式,当如下条件满足时,该模式被自动激活:
1. 查询串是空的(即长度为零)
2.
docinfo
存储方式为 extern
在完整扫描模式中,全部已索引的文档都被看作是匹配的。这类匹配仍然会被过滤、排序或
分组,但是并不会做任何真正的全文检索。这种模式可以用来统一全文检索和非全文检索的
代码,或者减轻
SQL 服务器的负担(有些时候 Sphinx 扫描的速度要优于类似的 MySQL 查
询)
4.2. 布尔查询
布尔查询允许使用下列特殊操作符:

显式的与(
AND)操作符
hello & world

或(
OR)操作符
hello | world

非(
NOT)操作符
hello -world
hello !world

分组(
grouping)
( hello world )
以下是一个使用了如上全部操作符的例子:
示例
5 布尔查询示例
( cat -dog ) | ( cat -mouse)

(AND)操作符为默认操作,所以“hello world”其实就是“hello & world”

(OR)操作符的优先级高于与操作符,因此“lookingfor cat | dog | mouse”意思是"looking for (
cat | dog | mouse )" 而不是 "(looking for cat) | dog | mouse"
像“
-dog”这种查询不能被执行,因为它差不多包括索引所有文档。这既有技术上的原因,
也有性能上的原因。从技术上说,
Sphinx 并不总是保持一个全部文档 ID 的列表。性能方面,
当文档集非常大的时候(即
10-100M 个文档),对这种执行查询可能需要很长的时间。
4.3. 扩展查询
在扩展查询模式中可以使用如下特殊操作符:

或(
OR)操作符
hello | world

非(
NOT)操作符
hello -world
hello !world

字段(
field)搜索符:
@title hello @body world

词组搜索符
"hello world"

近似搜索符
"hello world"~10

阀值匹配符
"the world is a wonderful place"/3
下例使用了上述大多数操作符:
示例
6 扩展查询示例
"hello world" @title "example program"~5 @body python -(php|perl)

(AND)操作为默认操作,因此“hello world”意思是“hello”和“world”必须同时存在文档才
能匹配。
或(
OR)操作符的优先级要高于与操作符,因此"looking for cat | dog | mouse" 意思

"looking for ( cat | dog | mouse )" 而不是"(looking for cat) | dog | mouse";
近似距离以词为单位,随词数变化而变化,并应用于引号中的全部词。举个例子,
"cat dog
mouse"~5 这个查询的意思是必须有一个少于 8 个词的词串,它要包含全部的三个词,也就
是说
"CAT aaa bbb ccc DOG eee fff MOUSE" 这个文档不会匹配这个查询,因为这个词串正好

8 个词。
阀值匹配符引入了一种模糊匹配。它允许至少含有某个阈值数量个匹配词的文档通过。上述
例子(
"the world is a wonderful place"/3)会匹配含有指定的六个词中的至少三个的那些文档。
类似如下查询中嵌套的括号
aaa | ( bbb ccc | ( ddd eee ) )
目前还是不允许的,但是这会在今后得以改进。
取否(也就是非(
NOT)操作符)只允许用在最外一层且不能在括号(也就是分组)里。这
个特性不会改变,因为支持嵌套的非操作会大大提高词组相关度计算实现的复杂性。
4.4.
权值计算
采用何种权值计算函数(目前)取决于查询的模式。
There are these major parts which are used in the weighting functions:
权值计算函数进行如下两部分主要部分:
1. 词组评分
2. 统计学评分
词组评分根据文档和查询的最长公共子串(
LCS,longest common subsequence)的长度进行。
因此如果文档对查询词组有一个精确匹配(即文档直接包含该词组),那么它的词组评分就
取得了可能的最大值,也就是查询中词的个数。
统计学评分基于经典的
BM25 函数,该函数仅考虑词频。如果某词在整个数据库中很少见
(即文档集上的低频词)或者在某个特定文档中被经常提及(即特定文档上的高频词),那
么它就得到一个较高的权重。最终的
BM25 权值是一个 0 到 1 之间的浮点数。
在所有模式中,数据字段的词组评分是
LCS 乘以用户指定的数据字段权值。数据字段权值
是整数,默认为
1,且字段的权值必须不小于 1。

SPH_MATCH_BOOLEAN 模式中,不做任何权重估计,每一个匹配项的权重都是 1。

SPH_MATCH_ALL 和 SPH_MATCH_PHRASE 模式中,最终的权值是词组评分的加权和。

SPH_MATCH_ANY 模式中,于前面述两模式的基本思想类似,只是每个数据字段的权重
都再加上一个匹配词数目。在那之前,带权的词组相关度被额外乘以一个足够大的数,以便
确保任何一个有较大词组评分的数据字段都会使整个匹配的相关度较高,即使该数据字段的
权重比较低。

SPH_MATCH_EXTENDED 模式中,最终的权值是带权的词组评分和 BM25 权重的和,再
乘以
1000 并四舍五入到整数。
这个行为将会被修改,以便使
MATCH_ALL 和 MATCH_ANY 这两个模式也能使用 BM25 算
法。这将使词组评分相同的搜索结果片断得到改进,这在只有一个词的查询中尤其有用。
关键的思想(对于除布尔模式以外的全部模式中)是子词组的匹配越好则评分越高,精确匹
配(匹配整个词组)评分最高。作者的经验是,这种基于词组相似性的评分方法可以提供比
任何单纯的统计模型(比如其他搜索引擎中广泛使用的
BM25)明显更高的搜索质量。
4.5.
排序模式
可使用如下模式对搜索结果排序:

SPH_SORT_RELEVANCE 模式, 按相关度降序排列(最好的匹配排在最前面)

SPH_SORT_ATTR_DESC 模式, 按属性降序排列 (属性值越大的越是排在前面)

SPH_SORT_ATTR_ASC 模式, 按属性升序排列(属性值越小的越是排在前面)

SPH_SORT_TIME_SEGMENTS 模式, 先按时间段(最近一小时/天/周/月)降序,再按
相关度降序

SPH_SORT_EXTENDED 模式, 按一种类似 SQL 的方式将列组合起来,升序或降序排
列。

SPH_SORT_EXPR 模式,按某个算术表达式排序。
SPH_SORT_RELEVANCE 忽略任何附加的参数,永远按相关度评分排序。所有其余的模式
都要求额外的排序子句,子句的语法跟具体的模式有关。
SPH_SORT_ATTR_ASC,
SPH_SORT_ATTR_DESC 以及 SPH_SORT_TIME_SEGMENTS 这三个模式仅要求一个属性名。
SPH_SORT_RELEVANCE 模式等价于在扩展模式中按"@weight DESC, @id ASC"排序,
SPH_SORT_ATTR_ASC 模式等价于"attribute ASC, @weight DESC, @id ASC",而
SPH_SORT_ATTR_DESC 等价于"attribute DESC, @weight DESC, @id ASC"。
SPH_SORT_TIME_SEGMENTS 模式

SPH_SORT_TIME_SEGMENTS 模式中,属性值被分割成“时间段”,然后先按时间段排
序,再按相关度排序。
时间段是根据搜索发生时的当前时间戳计算的,因此结果随时间而变化。所说的时间段有如
下这些值:

最近一小时

最近一天

最近一星期

最近一个月

最近三个月

其他值
时间段的分法固化在搜索程序中了,但如果需要,也可以比较容易地改变(需要修改源码)。
这种模式是为了方便对
Blog 日志和新闻提要等的搜索而增加的。使用这个模式时,处于更
近时间段的记录会排在前面,但是在同一时间段中的记录又根据相关度排序-这不同于单纯
按时间戳排序而不考虑相关度。
SPH_SORT_EXTENDED 模式

SPH_SORT_EXTENDED 模式中,您可以指定一个类似 SQL 的排序表达式,但涉及的属
性(包括内部属性)不能超过
5 个,例如:
@relevance DESC, price ASC, @id DESC
只要做了相关设置,不管是内部属性(引擎动态计算出来的那些属性)还是用户定义的属性
就都可以使用。内部属性的名字必须用特殊符号
@开头,用户属性按原样使用就行了。在上
面的例子里,
@relevance 和@id 是内部属性,而 price 是用户定义属性。
已知的内部属性:

@id (match ID)

@weight (match weight)

@rank (match weight)

@relevance (match weight)

@id(匹配的 ID)

@weight(匹配权值)

@rank(匹配权值)

@relevance(匹配权值)
@rank 和@relevance 只是@weight 的额外别名。
SPH_SORT_EXPR 模式
表达式排序模式使您可以对匹配项按任何算术表达式排序,表达式中的项可以是属性值,内
部属性(
@id 和@weight),算术运算符和一些内建的函数。例如:
$cl->SetSortMode ( SPH_SORT_EXPR,
"@weight + ( user_karma + ln(pageviews) )*0.1" );
支持的运算符和函数如下。它们是模仿
MySQL 设计的。函数接受参数,参数的数目根据具
体函数的不同而不同。

Operators: +, -, *, /, <, > <=, >=, =, <>.

Unary (1-argument) functions: abs(), ceil(), floor(), sin(), cos(), ln(), log2(), log10(), exp(),
sqrt().

Binary (2-argument) functions: min(), max(), pow().

Ternary (3-argument) functions: if().

运算符:
+, -, *, /, <, > <=, >=, =, <>.

一元函数(一个参数):
abs(), ceil(), floor(), sin(), cos(), ln(), log2(), log10(), exp(),
sqrt().

二元函数(两个参数):
min(), max(), pow().

三元函数(三个参数):
if().
全部的计算都以单精度
32 位 IEEE754 浮点数进行。比较操作符(比如=和<=)在条件为真
时返回
1.0,否则返回 0.0。例如(a=b)+3 在属性“a”与属性“b”相等时返回 4,否则返回
3。与 MySQL 不同,相等性比较符(即=和<>)中引入了一个小的阈值(默认是 1e-6)。
如果被比较的两个值的差异在阈值之内,则二者被认为相等。
全部的一元和二元函数的意义都很明确,他们的行为跟在数学中的定义一样。但
IF()的行为
需要点详细的解释。它接受
3 个参数,检查第一个参数是否为 0.0,若非零则返回第二个参
数,为零时则返回第三个参数。注意,与比较操作符不同,
IF()并不使用阈值!因此在第一
个参数中使用比较结果是安全的,但使用算术运算符则可能产生意料之外的结果。比如,下
面两个调用会产生不同的结果,虽然在逻辑上他们是等价的:
IF ( sqrt(3)*sqrt(3)-3<>0, a, b )
IF ( sqrt(3)*sqrt(3)-3, a, b )
在第一种情况下,由于有阈值,比较操作符
<>返回 0.0(逻辑假),于是 IF()总是返回

b’。在第二种情况下,IF()函数亲自在没有阈值的情况下将同样的
sqrt(3)*sqrt(3)-3 与零值做比较。但由于浮点数运算的精度问题,该表达式的结果与
0 值会有微小的差异,因此该值与零值的相等比较不会通过,上述第二种情况中 IF()会返
回‘a’做为结果。
4.6. 结果分组(聚类)
有时将搜索结果分组(或者说“聚类”)并对每组中的结果计数是很有用的-例如画个漂亮
的图来展示每个月有多少的
blog 日志,或者把 Web 搜索结果按站点分组,或者把找到的论
坛帖子按其作者分组。
理论上,这可以分两步实现:首先在
Sphinx 中做全文检索,再在 SQL 服务器端对得到的 ID
分组。但是现实中在大结果集(
10K 到 10M 个匹配)上这样做通常会严重影响性能。
为避免上述问题,
Sphinx 提供了一种“分组模式”,可以用 API 调用 SetGroupBy()来开启。
在分组时,根据
group-by 值给匹配项赋以一个分组。这个值用下列内建函数之一根据特定的
属性值计算:

SPH_GROUPBY_DAY,从时间戳中按 YYYYMMDD 格式抽取年、月、日

SPH_GROUPBY_WEEK,从时间戳中按 YYYYNNN 格式抽取年份和指定周数(自年
初计起)的第一天

SPH_GROUPBY_MONTH,从时间戳中按 YYYYMM 格式抽取月份

SPH_GROUPBY_YEAR,从时间戳中按 YYYY 格式抽取年份

SPH_GROUPBY_ATTR,使用属性值自身进行分组
最终的搜索结果中每组包含一个最佳匹配。分组函数值和每组的匹配数目分别以“虚拟”属

@group 和@count 的形式返回。
结果集按
group-by 排序子句排序,语法与
SPH_SORT_EXTENDED
排序子句的语法相似。除

@id 和@weight,分组排序子句还包括:

@group(groupby 函数值)

@count(组中的匹配数目)
默认模式是根据
groupby 函数值降序排列,即按照“@group desc”
排序完成时,结果参数
total_found 会包含在整个索引上匹配的组的总数目。
注意:分组操作在固定的内存中执行,因此它给出的是近似结果;所以
total_found 报告的数
目可能比实际给出的个分组数目的和多。
@count 也可能被低估。要降低不准确性,应提高
max_matches。如果 max_matches 允许存储找到的全部分组,那结果就是百分之百准确的。
例如,如果按相关度排序,同时用
SPH_GROUPBY_DAY 函数按属性“published”分组,那
么:

结果中包含每天的匹配结果中最相关的那一个,如果那天有记录匹配的话。

结果中还附加给出天的编号和每天的匹配数目

结果以天的编号降序排列(即最近的日子在前面)
4.7.
分布式搜索
为提高可伸缩性,
Sphnix 提供了分布式检索能力。分布式检索可以改善查询延迟问题(即缩
短查询时间)和提高多服务器、多
CPU 或多核环境下的吞吐率(即每秒可以完成的查询
数)。这对于大量数据(即十亿级的记录数和
TB 级的文本量)上的搜索应用来说是很关键
的。
其关键思想是将待搜索数据做水平分区(
HP,Horizontally partition),然后并行处理。
分区不能自动完成,您需要:

在不同服务器上设置
Sphinx 程序集(indexer 和 searchd)的多个实例

让这些实例对数据的不同部分做索引(并检索)


searchd 的一些实例上配置一个特殊的分布式索引

然后对这个索引进行查询
这个特殊索引只包括对其他本地或远程索引的引用,因此不能对它执行重新建立索引的操作,
相反,如果要对这个特殊索引进行重建,要重建的是那些被这个索引被引用到的索引。

searchd 收到一个对分布式索引的查询时,它做如下操作:
1. 连接到远程代理
2. 执行查询
3. (在远程代理执行搜索的同时)对本地索引进行查询
4. 接收来自远程代理的搜索结果
5. 将所有结果合并,删除重复项
6. 将合并后的结果返回给客户端
在应用程序看来,普通索引和分布式索引完全没有区别。
任一个
searchd 实例可以同时做为主控端(master,对搜索结果做聚合)和从属端(只做本地
搜索)。这有如下几点好处:
1. 集群中的每台机器都可以做为主控端来搜索整个集群,搜索请求可以在主控端之间获
得负载平衡,相当于实现了一种
HA(high availability,高可用性),可以应对某个
节点失效的情况。
2. 如果在单台多 CPU 或多核机器上使用,一个做为代理对本机进行搜索的 searchd 实例
就可以利用到全部的
CPU 或者核。
更好的
HA 支持已在计划之中,到时将允许指定哪些代理之间互相备份、有效性检查、跟踪
运行中的代理、对检索请求进行负载均衡,等等。
4.8.
searchd 日志格式
searchd 将全部成功执行的搜索查询都记录在查询日志文件中。以下是一个类似记录文件的
例子:
[Fri Jun 29 21:17:58 2007] 0.004 sec [all/0/rel 35254 (0,20)] [lj] test
[Fri Jun 29 21:20:34 2007] 0.024 sec [all/0/rel 19886 (0,20) @channel_id] [lj]
test
日志格式如下
[query-date] query-time [match-mode/filters-count/sort-mode
total-matches (offset,limit) @groupby-attr] [index-name] query
匹配模式(
match-mode)可以是如下值之一:

"all" 代表 SPH_MATCH_ALL 模式;

"any" 代表 SPH_MATCH_ANY 模式;

"phr" 代表 SPH_MATCH_PHRASE 模式;

"bool" 代表 SPH_MATCH_BOOLEAN 模式;

"ext" 代表 SPH_MATCH_EXTENDED 模式.
排序模式(
sort-mode)可以取如下值之一:

"rel" 代表 SPH_SORT_RELEVANCE 模式;

"attr-" 代表 SPH_SORT_ATTR_DESC 模式;

"attr+" 代表 SPH_SORT_ATTR_ASC 模式;

"tsegs" 代表 SPH_SORT_TIME_SEGMENTS 模式;

"ext" 代表 SPH_SORT_EXTENDED 模式.
5. API 参考
Sphnix 有几种不同编程语言的 searchd 客户端 API 的实现。在本文完成之时,我们对我们自
己的
PHP,Python 和 java 实现提供官方支持。此外,也有一些针对 Perl,Ruby 和 C++的第
三方免费、开源
API 实现。
API 的参考实现是用 PHP 写成的,因为(我们相信)较之其他语言,Sphinx 在 PHP 中应用
最广泛。因此这份参考文档基于
PHP API 的参考,而且这节中的所有的代码样例都用 PHP
给出。
当然,其他所有
API 都提供相同的方法,也使用完全相同的网络协议。因此这份文档对他们
同样适用。在方法命名习惯方面或者具体数据结构的使用上可能会有小的差别。但不同语言

API 提供的功能上绝不会有差异。
5.1. 通用 API 方法
5.1.1. GetLastError
原型:
function GetLastError()
以人类可读形式返回最近的错误描述信息。如果前一次
API 调用没有错误,返回空字符串。
任何其他函数(如
Query()
)失败后(函数失败一般返回
false),都应该调用这个函数,它
将返回错误的描述。
此函数本身并不重置对错误描述,因此如有必要,可以多次调用。
5.1.2. GetLastWarning
原型
: function GetLastWarning ()
Returns last warning message, as a string, in human readable format. If there were no warnings
during the previous API call, empty string is returned.
以人类可读格式返回最近的警告描述信息。如果前一次
API 调用没有警告,返回空字符串。
您应该调用这个函数来确认您的请求(如
Query()
)是否虽然完成了但产生了警告。例如,
即使几个远程代理超时了,对分布式索引的搜索查询也可能成功完成。这时会产生一个警告
信息。
此函数本身不会重置警告信息,因此如有必要,可以多次调用。
5.1.3. SetServer
原型:
function SetServer ( $host, $port )
设置
searchd 的主机名和 TCP 端口。此后的所有请求都使用新的主机和端口设置。默认的主
机和端口分别是“
localhost”和 3312。
5.1.4. SetRetries
原型
: function SetRetries ( $count, $delay=0 )
设置分布式搜索重试的次数和延迟时间。
对于暂时的失败,
searchd 对每个代理重试至多$count 次。$delay 是两次重试之间延迟的时间,
以毫秒为单位。默认情况下,重试是禁止的。注意,这个调用不会使
API 本身对暂时失败进
行重试,它只是让
searchd 这样做。目前暂时失败包括 connect()调用的各种失败和远程代理
超过最大连接数(过于繁忙)的情况。
5.1.5. SetArrayResult
原型:
function SetArrayResult ( $arrayresult )
PHP 专用。控制搜索结果集的返回格式(匹配项按数组返回还是按 hash 返回)
$arrayresult 参数应为布尔型。如果$arrayresult 为假(默认),匹配项以 PHP hash 格式返回,
文档
ID 为键,其他信息(权重、属性)为值。如果$arrayresult 为真,匹配项以普通数组返
回,包括匹配项的全部信息(含文档
ID)
这个调用是对
MVA 属性引入分组支持时同时引入的。对 MVA 分组的结果可能包含重复的
文档
ID。因此需要将他们按普通数组返回,因为 hash 对每个文档 ID 仅能保存一个记录。
5.</b>2. 通用搜索设置
5.2.1. SetLimits
原型
: function SetLimits ( $offset, $limit, $max_matches=0, $cutoff=0 )
给服务器端结果集设置一个偏移量(
$offset)和从那个偏移量起向客户端返回的匹配项数目
限制(
$limit)。并且可以在服务器端设定当前查询的结果集大小($max_matches),另有
一个阈值(
$cutoff),当找到的匹配项达到这个阀值时就停止搜索。全部这些参数都必须是
非负整数。
前两个参数的行为与
MySQL LIMIT 子句中参数的行为相同。他们令 searchd 从编号为$offset
的匹配项开始返回最多
$limit 个匹配项。偏移量($offset)和结果数限制($limit)的默认值分别是
0 和 20,即返回前 20 个匹配项。
max_match 这个设置控制搜索过程中 searchd 在内存中所保持的匹配项数目。一般来说,即
使设置了
max_matches 为 1,全部的匹配文档也都会被处理、评分、过滤和排序。但是任一
时刻只有最优的
N 个文档会被存储在内存中,这是为了性能和内存使用方面的原因,这个设
置正是控制这个
N 的大小。注意,max_matches 在两个地方设置。针对单个查询的限制由这

API 调用指定。但还有一个针对整个服务器的限制,那是由配置文件中的 max_matches 设
置控制的。为防止滥用内存,服务器不允许单个查询的限制高于服务器的限制。
在客户端不可能收到超过
max_matches 个匹配项。默认的限制是 1000,您应该不会遇到需要
设置得更高的情况。
1000 个记录足够向最终用户展示了。如果您是想将结果传输给应用程
序以便做进一步排序或过滤,那么请注意,在
Sphinx 端完成效率要高得多。
$cutoff 设置是为高级性能优化而提供的。它告诉 searchd 在找到并处理$cutoff 个匹配后就强
制停止。
5.2.2. SetMaxQueryTime
原型
: function SetMaxQueryTime ( $max_query_time )
设置最大搜索时间,以毫秒为单位。参数必须是非负整数。默认值为
0,意思是不做限制。
这个设置与
SetLimits()中的$cutoff 相似,不过这个设置限制的是查询时间,而不是处理的匹
配数目。一旦处理时间已经太久,本地搜索查询会被停止。注意,如果一个搜索查询了多个
本地索引,那这个限制独立地作用于这几个索引。
5.3. 全文搜索设置
5.3.1. SetMatchMode
原型
: function SetMatchMode ( $mode )
设置全文查询的匹配模式,参见节
4.1 “匹配模式”中的描述。参数必须是一个与某个已知模
式对应的常数。
警告:(仅
PHP)查询模式常量不能包含在引号中,那给出的是一个字符串而不是一个常量。
$cl->SetMatchMode ( "SPH_MATCH_ANY" ); // INCORRECT! will not work as expected
$cl->SetMatchMode ( SPH_MATCH_ANY ); // correct, works OK
5.3.2. SetRankingMode
原型
: function SetRankingMode ( $ranker )
设置评分模式。目前只在
SPH_MATCH_EXTENDED2 这个匹配模式中提供。参数必须是与
某个已知模式对应的常数。
 
1  /  1  页   1 跳转

版权所有 流水日志  希望网络 流水 YPState 理想论坛 8671  Sitemap

Powered by Discuz!NT 2.0.1214    Copyright © 2012 论坛网址.
Processed in 0.09375 second(s) , 4 queries.
返顶部