圣泉山人 后端开发工程师

Sphinx

2016-04-05
PHP

什么是coreseek?

coreseek是一款基于sphinx开源的搜索引擎。专门为用户提供免费的中文全文检索系统,与sphinx不同的是增加了一个带有中文分词的词库

运行原理

image

coreseek在windows下的安装

1、下载coreseek的windows包,解压后,主要的目录结构如下:

|-- coreseek-3.2.14
|   |-- api  包括java,ruby,C/C++,php的sphinx访问api接口
|   |-- bin  coreseek主要的可执行文件
|   |-- etc  配置文件存放位置
|   |-- var  索引文件存放位置

2、在etc目录下创建好配置文件,比如:fc.conf

3、通过命令行进入到coreseek存放位置,使用命令创建索引:

indexer -c <file> --rotate --all
选项 含义
-c 或者–config 后跟配置文件路径
--rotate 轮换索引,建立一个额外的索引,并用索引名后加一个“new”标识,完成后,把旧索引文件重命名,再重命名新索引文件,达到替换索引文件的目的
–all 对配置文件中全部的索引进行操作,也可以不用all,而操作指定的索引

USAGE

D:\coreseek\bin
λ indexer -c D:/coreseek/etc/fc.conf --rotate --all
Coreseek Fulltext 3.2 [ Sphinx 0.9.9-release (r2117)]
Copyright (c) 2007-2011,
Beijing Choice Software Technologies Inc (http://www.coreseek.com)

using config file 'D:/coreseek/etc/fc.conf'...
indexing index 'store'...
collected 70 docs, 0.0 MB
sorted 0.0 Mhits, 100.0% done
total 70 docs, 3839 bytes
total 0.970 sec, 3955 bytes/sec, 72.12 docs/sec
indexing index 'delta_store'...
collected 0 docs, 0.0 MB
total 0 docs, 0 bytes
total 0.087 sec, 0 bytes/sec, 0.00 docs/sec
...

4、启动服务,使用一条简单的命令即可完成启动:

searchd -c <file> 

<file> 表示配置文件路径。此时服务会默认运行在9312端口,如果需要让其运行在其他端口,可以在配置文件里面进行修改或者使用 -p选项指定运行的端口,一些其他选项:

选项 含义
-p 指定运行端口
--iostats 会记录更详细的日志信息
--cpustats CPU时间报告

如果要安装成window系统服务的话使用命令:

searchd.exe --install -c <file> --servicename <服务名>   

USAGE

D:\coreseek\bin
λ searchd -c D:/coreseek/etc/fc.conf
Coreseek Fulltext 3.2 [ Sphinx 0.9.9-release (r2117)]
Copyright (c) 2007-2011,
Beijing Choice Software Technologies Inc (http://www.coreseek.com)

WARNING: forcing --console mode on Windows
using config file 'D:/coreseek/etc/fc.conf'...
listening on all interfaces, port=9312
accepting connections

配置文件

一个典型的增量索引主要组成:

#索引1:
source 数据源1
{           
    ...
}
source 增量1 : 数据源1
{
    ...
}
index 数据源
{
    source=源名称1
    ...
}
index 增量
{
    source=增量1
    ...
}

#索引2
...
#索引3
...

#全局index定义
Indexer{
    ...
}

#服务本身的配置
searchd{                             
    ...
}

USAGE

#索引1
source src_store                                #数据源
{
    type                    = mysql
    sql_host                = localhost
    sql_user                = root
    sql_pass                = myy545
    sql_db                  = db_fengche
    sql_port                = 3306
    sql_query_pre           = SET NAMES utf8    #indexer的sql执行前需要执行的操作
	
    #数据表计数
    sql_query_pre = REPLACE INTO sph_counter SELECT 1, MAX(store_id) FROM fc_store

    #数据源:从哪些数据表里面获取哪些数据用来建立索引,第一列需为整数类型
    sql_query  = SELECT s.store_id,s.store_name,s.region_id,s.description,s.state,s.credit_value,s.sort_order,m.user_name,cs.cate_id FROM fc_store AS s LEFT JOIN fc_member AS m ON m.user_id=s.store_id LEFT JOIN fc_category_store AS cs ON cs.store_id=s.store_id WHERE s.store_id <= (SELECT max_id FROM sph_counter WHERE id=1)
    
    #通过api过滤的属性(即需要被用作条件筛选的字段)都要在定义出来
    #sql_attr_uint:        无符号整形属性
    #sql_attr_bool:        布尔属性
    #sql_attr_timestamp:   时间戳属性,经常被用于做排序
    #sql_attr_float:       浮点数属性
    #sql_attr_multi:       复合属性,用于筛选逗号隔开的字段数据
    #sql_attr_string:      字符串属性
    
    sql_attr_float = credit_value               
    sql_attr_uint  = region_id
    sql_attr_uint  = state
    sql_attr_uint  = credit_value
    sql_attr_uint  = sort_order
    sql_attr_multi = uint cate_id from field
}
#店铺增量
source delta_src_store : src_store
{
    #当数据源过大时,可以采用分次查询,通过定义:范围(sql_query_range)、步长(sql_range_step)、时间间隔(sql_ranged_throttle):
    sql_ranged_throttle	= 100
    sql_query_pre 	= SET NAMES utf8    #必须显式的设置sql_query_pre,否则会执行前面的REPLACE语句
    sql_query           = SELECT s.store_id,s.store_name,s.region_id,s.description,s.state,s.credit_value,s.sort_order,m.user_name,cs.cate_id FROM fc_store AS s LEFT JOIN fc_member AS m ON m.user_id=s.store_id LEFT JOIN fc_category_store AS cs ON cs.store_id=s.store_id WHERE s.store_id > (SELECT max_id FROM sph_counter WHERE id=1)
}

#index定义
#店铺
index store
{
    source      = src_store                 #对应的source名称
    path        = D:/coreseek/var/fc/store  #索引存放路径
    docinfo     = extern                    #文档信息的存储模式,包括有none,extern,inline。默认是extern
    mlock       = 0                         #缓冲内存锁定
    morphology	= none                      #词形处理器,一般用于处理单词
    min_word_len= 1                         #最小索引词长度,小于这个长度的词不会被索引
    html_strip  = 0                         #是否从输出全文数据中去除HTML标记
    charset_dictpath = D:/coreseek/etc/     #BSD、Linux环境下设置,/符号结尾
    charset_type= zh_cn.utf-8
    #stopwords	= /path/to/stowords.txt的位置
    #charset_table=......	            #必须注释掉(字符关系映射表)
    ngram_len	= 0                         #N-Gram索引的分词技术,使用了中文分词后,需设置为0-禁用
}

#店铺增量
index delta_store : store
{
    source 	= delta_src_store
    path	= D:/coreseek/var/fc/delta_store
    #morphology	= stem_en
}

# 全局index定义
indexer
{
    mem_limit = 128M                        #建立索引的时候,索引内存限制
}

#searchd服务配置
searchd
{
    listen               	= 9312                  #运行端口
    read_timeout         	= 5                     #客户端请求的读超时时间 
    max_children         	= 30                    #子进程的最大数量
    max_matches          	= 10000                 #内存中为每个索引所保持并返回给客户端的匹配数目的最大值
    seamless_rotate     	= 0                     #为1的话:任何时刻查询都可用
    preopen_indexes      	= 0                     #为1的话:启动时强制重新打开所有索引文件
    unlink_old           	= 1                     #设置索引轮转成功以后删除以.old为扩展名的索引拷贝      
    pid_file = D:/coreseek/var/log/searchd_mysql.pid    #设置searchd进程pid文件名
    log = D:/coreseek/var/log/searchd_mysql.log         #定义日志存放目录
    query_log = D:/coreseek/var/log/query_mysql.log     #定义查询日志目录
}

Sphinx守护进程会自动对增量索引进行自动更新,但是之前的数据如果有变动就需要在业务代码里面手动的去更新对应的索引属性 ,PHP使用UpdateAttributes()进行更新

php对Sphinx的操作使用

1、引入php操作Sphinx的类文件:

include 'SphinxClient.php';

2、初始化(连接)Sphinx:

$sphinx = new SphinxClient();
$sphinx->SetServer($host, $port);

3、属性过滤(设定搜索条件),前提是属性在配置文件中有配置,否则会报错

USAGE

//credit_value的取值范围是1.2-2.5(包含)
$sphinx->SetFilterFloatRange('credit_value', 1.2, 2.5);

//region_id的取值是11或者13
$sphinx->SetFilter('region_id', array(11,13));

//cate_id是复合属性比如字段数据是1,4,20,25,29 。那么下面的过滤则要求cate_id中同时存在1和21
$sphinx->SetFilter('cate_id', array(1));
$sphinx->SetFilter('cate_id', array(21));

4、对结果进行设定

USAGE

//设置结果是数组格式
$sphinx->SetArrayResult(true);

//对结果进行分组,第一个参数是分组字段,第二个参数是排序模式,第三个参数是排序规则,此时的排序规则会影响最终结果的排序
$sphinx->SetGroupBy('store_id', SPH_GROUPBY_ATTR);

//设置排序规则,如果同时设置了SetGroupBy,则SetSortMode只会影响到组内排序
$sphinx->SetSortMode(SPH_SORT_EXTENDED, "@id DESC");

//按照关键词搜索:为了安全转义特殊字符->提取关键词->处理结果成搜索字符串
$keyword = $sphinx->EscapeString($keyword);
$build_kws = $sphinx->BuildKeywords($keyword, 'store', false);
if(is_array($build_kws)) {
    foreach($build_kws as $v) {
        $kw[] = $v['normalized'];
    }
    $kw = array_unique($kw);
}
$query .= ' @(store_name,description) (' . implode('|', $kw) . ')';

//对结果进行分页,第三个参数是最大匹配数
$sphinx->SetLimits($limit['begin'], $limit['offset'], SPHINX_MAX_MATACHES);

//最终的结果查询,需要的主键id数据在$res['matches']中
$res = $sphinx->Query($query, "store,delta_store");

实时索引

增量索引,优点:在于对数据量比较多的记录,只会在第一次建立索引的时候花费时间比较长,后续数据有新增,Sphinx都会自动把增量加载回来。缺点:对于已经存在的数据发生变更是不会主动做出相应修改的,只能人为地在业务代码里去告知Sphinx哪条索引需要修改。因此增量索引只是近似于实时更新,但是始终存在时间差,需要去衡量在这段时间内的‘脏数据’对业务的影响是否在可接受范围。

Sphinx目前还支持一种实时索引,其原理是:使用sphinxQLmysql41协议进行查询添加更新数据。新更新进去的数据会自动索引达到实时索引的程度。其缺点是:更新频繁或者数据量大时会导致内存压力增长、内存数据写盘不及时容易丢失、目前只支持部分SQL语句。

USAGE

index rt
{
    type = rt               #类型指定为实时索引类型
    rt_mem_limit = 512M
    path = /usr/local/sphinx/data/rt
    rt_field = title
    rt_field = content
    rt_attr_uint = gid
}
searchd
{
  workers           = threads
  listen            = 3312
  listen            = 3313:mysql41
  log               = /usr/local/sphinx/var/log/searchd.log
  query_log         = /usr/local/sphinx/var/log/query.log
  read_timeout      = 5
  client_timeout    = 300
  max_children      = 30
  pid_file          = /usr/local/sphinx/var/log/searchd.pid
  max_matches       = 1000
  seamless_rotate   = 1
  preopen_indexes   = 1
  unlink_old        = 1
}

实时索引不需要indexer,直接开启searchd即可。


上一篇 Exception

下一篇 Socket

Comments

Content