• 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:lue下,解压缩后sphinx根目录为D:luesphinx-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:luesphinx_data,另外这个目录下建立两个目录data和log,不知道什么原因,系统无法自动创建这两个目录,会出错。
        另外在本机新建一个sphinx数据库,字符集选择utf-8,然后运行D:luesphinx-2.2.8-release-win64-full下的example.sql,需要注意将其中的数据库前缀test.更换为sphinx.,表示在sphinx数据库中创建表,创建之后,在sphinx下检查一下,看是否存在documents和tags两张表。
        然后在D:luesphinx-2.2.8-release-win64-fullin下,运行indexer -c ..sphinx-min.conf.in --all ,如下
    D:luesphinx-2.2.8-release-win64-fullin>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:luesphinx-2.2.8-release-win64-fullin>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:luesphinx-2.2.8-release-win64-fullin>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:luesphinx-for-chinese-2.2.1-dev-r4311-win32sphinf-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:luesphinx-for-chinese-2.2.1-dev-r4311-win32xdict
    }
    其中charset_type = utf-8在最新的版本中已经废弃,因为默认已经是utf-8,xdict是一个字典文件
            xdict是一个字典文件,可以从https://sphinx-for-chinese.googlecode.com/files/xdict_1.1.tar.gz下载,然后解压缩,用mkdict命令生成字典,如下:binmkdict.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,但是如果只搜索单字“重”,是没有数据的,这是不一样的地方。
         
     
           
           
         

     

  • 相关阅读:
    USACO Training Section 1.2 [USACO1.2]回文平方数
    USACO Training Section 1.2 双重回文数 Dual Palindrom
    USACO Training Section 1.2 双重回文数 Dual Palindrom
    USACO Training Section 1.2 [USACO1.2]方块转换 Transformations
    USACO Training Section 1.2 [USACO1.2]方块转换 Transformations
    USACO Training Section 1.2 挤牛奶Milking Cows
    USACO Training Section 1.2 挤牛奶Milking Cows
    FZU 1894 志愿者选拔
    FZU 1894 志愿者选拔
    Java实现 LeetCode 705 设计哈希集合(使用数组保存有没有被用过)
  • 原文地址:https://www.cnblogs.com/stone-fly/p/4377456.html
Copyright © 2020-2023  润新知