Sphinx学习笔记(一)

最近负责一个项目,需要用到全文检索,我的环境大体如下:

 
    1、数据保存在MySQL中
    2、需要支持中文检索
    3、尽可能的简单
 
    选择了Sphinx,至于solr和Elasticsearch,看主页的介绍,它们对分布式、均衡等方面的支持非常好,只不过它们的安装包太大了,用起来挺不方便的,所以才放弃了它们,不过等有机会还可以研究一下。
 
    基本步骤如下:
   1、 安装:Sphinx的主页是http://sphinxsearch.com/,目前版本为2.2.8,下载界面为http://sphinxsearch.com/downloads/release/,分为32位和64位版本,还分为windows、debian/ubuntu,Fedora/Centos版本,也可以直接下载源代码,进行编译安装,我主要在windows上测试,在Centos上部署,简述过程如下
      1)Windows 8.1 X64 , sphinx 2.2.8 (Win64 binaries w/MySQL+PgSQL+libstemmer+id64 support)
      将压缩包解压缩到d:\blue下,解压缩后sphinx根目录为D:\blue\sphinx-2.2.8-release-win64-full。
      修改配置文件sphinx-min.conf.in,相对简单一下
#
# Minimal Sphinx configuration sample (clean, simple, functional)
#
#数据源,src1为名字,后面会引用这个名字
source src1
{
 type = mysql
 
 sql_host = localhost
 sql_user = test
 sql_pass =
 sql_db = test
 sql_port = 3306 # optional, default is 3306
 
 sql_query = \
  SELECT id, group_id, UNIX_TIMESTAMP(date_added) AS date_added, title, content \
  FROM documents
 
 sql_attr_uint = group_id
 sql_attr_timestamp = date_added
}
 
#test1为索引名称,sphinx检索时需要这个名字,相当于关系数据库中的table
index test1
{
 source = src1 #引用的数据源名称
 path = @CONFDIR@/data/test1
}
 
 
index testrt
{
 type = rt
 rt_mem_limit = 128M
 
 path = @CONFDIR@/data/testrt
 
 rt_field = title
 rt_field = content
 rt_attr_uint = gid
}
 
 
indexer
{
 mem_limit = 128M
}
 
 
searchd
{
 listen = 9312
 listen = 9306:mysql41
 log = @CONFDIR@/log/searchd.log
 query_log = @CONFDIR@/log/query.log
 read_timeout = 5
 max_children = 30
 pid_file = @CONFDIR@/log/searchd.pid
 seamless_rotate = 1
 preopen_indexes = 1
 unlink_old = 1
 workers = threads # for RT to work
 binlog_path = @CONFDIR@/data
}
       具体修改步骤如下,修改source src1下的mysql连接信息,包括主机、用户名、密码、数据库、端口,sql_query是数据源中的sql,这里是从mysql中抽取数据,sql_attr_*是用来分组排序用的,如果我们需要对一些字段进行排序操作,需要在这里定义,另外需要替换@CONFDIR@为你想要的目录,我的修改如下
#
# Minimal Sphinx configuration sample (clean, simple, functional)
#
 
source src1
{
 type = mysql
 
 sql_host = localhost
 sql_user = root
 sql_pass = 
 sql_db = sphinx
 sql_port = 3306 # optional, default is 3306
 
 sql_query = \
  SELECT id, group_id, UNIX_TIMESTAMP(date_added) AS date_added, title, content \
  FROM documents
 
 sql_attr_uint = group_id
 sql_attr_timestamp = date_added
 sql_query_pre = SET NAMES utf8
}
 
 
index test1
{
 source = src1
 path = D:/blue/sphinx_data/data/test1
 
 ngram_len = 1
 ngram_chars = U+4E00..U+9FBB, U+3400..U+4DB5, U+20000..U+2A6D6, U+FA0E, U+FA0F, U+FA11, U+FA13, U+FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27, U+FA28, U+FA29, U+3105..U+312C, U+31A0..U+31B7, U+3041, U+3043, U+3045, U+3047, U+3049, U+304B, U+304D, U+304F, U+3051, U+3053, U+3055, U+3057, U+3059, U+305B, U+305D, U+305F, U+3061, U+3063, U+3066, U+3068, U+306A..U+306F, U+3072, U+3075, U+3078, U+307B, U+307E..U+3083, U+3085, U+3087, U+3089..U+308E, U+3090..U+3093, U+30A1, U+30A3, U+30A5, U+30A7, U+30A9, U+30AD, U+30AF, U+30B3, U+30B5, U+30BB, U+30BD, U+30BF, U+30C1, U+30C3, U+30C4, U+30C6, U+30CA, U+30CB, U+30CD, U+30CE, U+30DE, U+30DF, U+30E1, U+30E2, U+30E3, U+30E5, U+30E7, U+30EE, U+30F0..U+30F3, U+30F5, U+30F6, U+31F0, U+31F1, U+31F2, U+31F3, U+31F4, U+31F5, U+31F6, U+31F7, U+31F8, U+31F9, U+31FA, U+31FB, U+31FC, U+31FD, U+31FE, U+31FF, U+AC00..U+D7A3, U+1100..U+1159, U+1161..U+11A2, U+11A8..U+11F9, U+A000..U+A48C, U+A492..U+A4C6
 
}
 
 
index testrt
{
 type = rt
 rt_mem_limit = 128M
 
 path = D:/blue/sphinx_data/data/testrt
 
 rt_field = title
 rt_field = content
 rt_attr_uint = gid
}
 
 
indexer
{
 mem_limit = 128M
}
 
 
searchd
{
 listen = 9312
 listen = 9306:mysql41
 log = D:/blue/sphinx_data/log/searchd.log
 query_log = D:/blue/sphinx_data/log/query.log
 read_timeout = 5
 max_children = 30
 pid_file = D:/blue/sphinx_data/log/searchd.pid
 seamless_rotate = 1
 preopen_indexes = 1
 unlink_old = 1
 workers = threads # for RT to work
 binlog_path = D:/blue/sphinx_data/data
}
 
    修改的内容如黑体字所示,需要注意的是sql_query_pre, ngram_len,ngram_chars,这些都是支持中文检索必须的,如果没有的话,无法支持中文,另外将@CONFDIR@替换为d:\blue\sphinx_data,另外这个目录下建立两个目录data和log,不知道什么原因,系统无法自动创建这两个目录,会出错。
    另外在本机新建一个sphinx数据库,字符集选择utf-8,然后运行D:\blue\sphinx-2.2.8-release-win64-full下的example.sql,需要注意将其中的数据库前缀test.更换为sphinx.,表示在sphinx数据库中创建表,创建之后,在sphinx下检查一下,看是否存在documents和tags两张表。
    然后在D:\blue\sphinx-2.2.8-release-win64-full\bin下,运行indexer -c ..\sphinx-min.conf.in --all ,如下
D:\blue\sphinx-2.2.8-release-win64-full\bin>indexer -c ..\sphinx-min.conf.in --all
Sphinx 2.2.8-id64-release (r4942)
Copyright (c) 2001-2015, Andrew Aksyonoff
Copyright (c) 2008-2015, Sphinx Technologies Inc (http://sphinxsearch.com)
 
using config file '..\sphinx-min.conf.in'...
indexing index 'test1'...
collected 4 docs, 0.0 MB
sorted 0.0 Mhits, 100.0% done
total 4 docs, 33882 bytes
total 0.121 sec, 278900 bytes/sec, 32.92 docs/sec
skipping non-plain index 'testrt'...
total 3 reads, 0.000 sec, 12.0 kb/call avg, 0.0 msec/call avg
total 12 writes, 0.001 sec, 5.7 kb/call avg, 0.1 msec/call avg
需要注意的是,如果需要建立的索引已经被使用,即已经启动了searchd服务,就需要增加--rotate参数,类似于
indexer -c ..\sphinx-min.conf.in --all --rotate

然后在同一目录下运行 searchd -c ..\sphinx-min.conf.in,如下

D:\blue\sphinx-2.2.8-release-win64-full\bin>searchd -c ..\sphinx-min.conf.in
Sphinx 2.2.8-id64-release (r4942)
Copyright (c) 2001-2015, Andrew Aksyonoff
Copyright (c) 2008-2015, Sphinx Technologies Inc (http://sphinxsearch.com)
 
using config file '..\sphinx-min.conf.in'...
listening on all interfaces, port=9312
listening on all interfaces, port=9306
precaching index 'test1'
rotating index 'test1': success
precaching index 'testrt'
precached 2 indexes in 0.045 sec

没有什么错误,需要注意的是,需要先创建索引,才能启动服务,否则可能会出错,searchd命令也可以安装为服务,以后使用起来会更加方便,这里这么做也是为了看到底是否配置成功,否则系统服务出错,我们看不到错误原因。

    查看searchd的输出或者sphinx-min.conf.in的searchd的配置项,可以知道sphinx在两个端口监听,9312,9306,其中9312是Sphinx API访问的端口,9306是SphinxQL的,SphinxQL是一个Mysql接口,可以通过mysql客户端访问。
2、SphinxQL
     SPihinxQL是一种mysql接口,可以通过sql语句来执行查询,可以用mysql命令行工具,也可以使用mysql的客户端工具,如HeidiSQL,这个是我常常使用的mysql客户端,配置连接很简单,用户名密码不用填,只要设置主机和端口就可以了,端口通常为9306,命令行如下
     >mysql -h localhost -P9306
     下面就可以使用SphinxQL了
     mysql中的数据如下
id group_id group_id2 date_added title content
1 1 5 2015/3/27 16:53 test one this is my test document number one. also checking...
2 1 6 2015/3/27 16:53 test two this is my test document number two
3 2 7 2015/3/27 16:53 another doc this is another group
4 2 8 2015/3/27 16:53 doc number four this is to test groups
   运行SphinxQL,
  mysql> select * from test1 where match('my');
+------+----------+------------+
| id   | group_id | date_added |
+------+----------+------------+
|    1 |        1 | 1427446411 |
|    2 |        1 | 1427446411 |
+------+----------+------------+
2 rows in set (0.00 sec)
     可以看出这里面并不包含数据,只包含数字字段:id和group_id,所以如果想得到数据,需要在mysql中重新查询数据才能得到结果。
     下面修改一下数据,改成中文,如下
id group_id group_id2 date_added title content
1 1 5 2015/3/27 16:53 test one this is my test document number one. also checking...
2 1 6 2015/3/27 16:53 test two this is my test document number two
3 2 7 2015/3/27 16:53 another doc 代码到了一定时间,必须重构,否则会出现问题
4 2 8 2015/3/27 16:53 doc number four 重庆制造到了最后阶段了,车体构造已经完成,就等待最后的出厂了
      重新生成索引,
      D:\blue\sphinx-2.2.8-release-win64-full\bin>indexer -c ..\sphinx-min.conf.in --all --rotate
 

Sphinx 2.2.8-id64-release (r4942)

 

Copyright (c) 2001-2015, Andrew Aksyonoff

 

Copyright (c) 2008-2015, Sphinx Technologies Inc (http://sphinxsearch.com)

 
 

using config file '..\sphinx-min.conf.in'...

 

indexing index 'test1'...

 

collected 4 docs, 0.0 MB

 

sorted 0.0 Mhits, 100.0% done

 

total 4 docs, 303 bytes

 

total 0.086 sec, 3518 bytes/sec, 46.44 docs/sec

 

skipping non-plain index 'testrt'...

 

total 3 reads, 0.000 sec, 0.4 kb/call avg, 0.0 msec/call avg

 

total 12 writes, 0.001 sec, 0.2 kb/call avg, 0.0 msec/call avg

 

rotating indices: successfully sent SIGHUP to searchd (pid=4556).

 
     中文查询就无法在mysql命令行中执行了,这是在windows的情况下,因为其中文字符不是UTF-8,会出现无法搜索出结果的现象,需要用HeidiSQL之类的,运行查询,
     select * from test1 where match('重构');
"id" "group_id" "date_added"
"3" "2" "1427446411"
"4" "2" "1427446411"

这里面有一个问题,可以看出id 4实际上并没有“重构”这个词,只是包含“重”“构”这两个字而已,所以可能无法满足某些需求,但是好在Sphinx的默认匹配方式是短语相似度,所以理论上来说,包含“重构”这个词的会排序在前面,简单测试也是如此,是否一直如此就不知道了。可以参考这篇文章:http://rainkid.blog.163.com/blog/static/165140840201010277223611/

3、Nodejs查询Sphinx
   1)Sphinxapi
        首页在https://github.com/lindory-project/node-sphinxapi/tree/master,安装方式: npm install sphinxapi
        文档比较详细,简单实用如下
        #sphinx2.js
var SphinxClient = require ("sphinxapi"),
    util = require('util'),
    assert = require('assert');
 
var cl = new SphinxClient();
cl.SetServer('localhost', 9312);
cl.Query('重构','test1', function(err, result) {
        assert.ifError(err);
        console.log(util.inspect(result, false, null, true));
});
运行程序,node sphinx2.js,如下
{ error: '',
  warning: '',
  status: [ 0 ],
  fields: [ 'title', 'content' ],
  attrs:
   [ [ 'group_id', 1 ],
     [ 'date_added', 2 ] ],
  matches:
   [ { id: 3,
       weight: 2,
       attrs: { group_id: 2, date_added: 1427446411 } },
     { id: 4,
       weight: 1,
       attrs: { group_id: 2, date_added: 1427446411 } } ],
  total: 2,
  total_found: 2,
  time: 0.004,
  words:
   [ { word: '重', docs: 2, hits: 2 },
     { word: '构', docs: 2, hits: 2 } ] }
可以看出和SphinxQL运行的效果一样,只不过返回的信息更多而已。

2)SphinxQL

       SphinxQL需要SphinxAPI的支持,所以在安装sphinxapi包的基础上,还需要安装node-mysql包,命令为npm install mysql
       简单例子如下
#sphinx.js
var mysql = require('mysql');
 
var connection = mysql.createConnection(
    {
      host      : 'localhost',
      port : '9306'
    }
);
 
connection.connect();
 
var queryString = "SELECT * FROM test1 WHERE MATCH('重构')";
 
connection.query(queryString, function(err, rows, fields) {
    if (err) throw err;
 
    for (var i in rows) {
        console.log(JSON.stringify(rows[i]));
    }
});
 
connection.end();
 
运行程序,node sphinx.js,如下
{"id":3,"group_id":2,"date_added":1427446411}
{"id":4,"group_id":2,"date_added":1427446411}
 
乍看起来,似乎sphinxapi提供的信息更多,我没有具体比较过,不过sphinxQL也包含了一些函数,如weight(),可以返回权重,如执行SELECT *, weight() FROM test1 WHERE MATCH('重构'); 结果如下
"id" "group_id" "date_added" "weight()"
"3" "2" "1427446411" "2557"
"4" "2" "1427446411" "1557"
可知sphinxap提供的权重,似乎是sphinxQL提供的值除以1000之后的值

3、CentOS的安装和使用

       CentOS的使用没什么特别的,最好是下载rpm安装包,过程如下
$ yum install postgresql-libs unixODBC
$ rpm -Uhv sphinx-2.2.8.rhel6.x86_64.rpm
$ service searchd start
具体的使用和Windows是一样的,没有什么区别。

4、其他

        1)最好的文档来源是官方文档,比较详细,内容也较多
        2)如果对信息的实时性要求较高,可以使用实时索引,具体内容我没有仔细研究过,以后有机会研究吧
        3)索引合并,如果原数据较多,新增加的数据不多,可以采用增量更新索引的办法,命令如下
indexer --merge DSTINDEX SRCINDEX [--rotate]
        srcindex会更新到dstindex上,如果目标索引正在使用,需要使用--rotate参数
        需要注意的是,如果发生重复现象,原始索引的数据并不会删除,如果要达到这一目的,可以运行
indexer --merge main delta --merge-dst-range deleted 0 0
        在某些情况下,这种方式较为有用,如每隔一小时合并一次索引,晚上重建一次索引,如果数据规模过大,就需要考虑分布式了,这个问题就比较复杂了,需要另外研究了。
        4)sql_query_pre = SET NAMES utf8 
         这个设置有些奇怪,我在文档中并没有查到这个信息,,但是不设置这个,就无法生成中文索引,后来还是在sphinx群中咨询了一下,“熊熊熊熊”同学看了我的配置文件,指出了这个问题,我才得以继续使用sphinx,否则我都要放弃sphinx了,这里要对“熊熊熊熊”同学表示感谢。不知道是不是windows 8的原因,不过在linux下也需要设置这个参数,不知道为什么。
       5)安装为服务(windows 8. 1)
        RPM和DEB包自动安装服务,在windows下,需要运行seachd命令将其安装为服务:
     searchd --install -c D:\blue\sphinx-for-chinese-2.2.1-dev-r4311-win32\sphinf-min.conf.in 服务名
        如果不指定服务名,会在windows服务列表中生成一个名为search的服务。
        在测试时,最好用searchd命令行运行,不要安装为服务,因为没有输出会比较麻烦,出了问题不好解决。
        删除服务: sc delete 服务名
  5、sphinx for chinese的配置问题(windows 8.1)
       sphinx for chinese的版本有点旧了,最新的如下
        其使用方式也比较简单,需要在配置文件中修改索引项,如下
index test1
{
 source = src1
 path = D:/blue/sphinx_data/data/test1
 docinfo = extern
 charset_type = utf-8
 chinese_dictionary = D:\blue\sphinx-for-chinese-2.2.1-dev-r4311-win32\xdict
}
其中charset_type = utf-8在最新的版本中已经废弃,因为默认已经是utf-8,xdict是一个字典文件
        xdict是一个字典文件,可以从https://sphinx-for-chinese.googlecode.com/files/xdict_1.1.tar.gz下载,然后解压缩,用mkdict命令生成字典,如下:bin\mkdict.exe xdict_1.1.txt xdict
      Sphinx for chinese用起来也很方便,但是有一个不一样的地方,还是使用上面的数据,运行SphinxQL,
      select *,weight() from test1 where match('重构');
      "id" "group_id" "date_added" "weight()"
      "3" "2" "1427446411" "1695"
      可以看出这次可以精确找到id为3的数据,没有搜索到4,但是如果只搜索单字“重”,是没有数据的,这是不一样的地方。
     
 
       
       
     
上一篇:play1.x vs play2.x 对比(转)


下一篇:EPD的驱动