公司项目刚刚导入大量产品数据,然后发现网站的产品搜索很卡,原本是原生sql的like来做模糊搜索,数据量20W的时候还可以接受,但是上百万就很卡了,所以需要做优化。

经过考虑,打算采用全文检索 sphinx + 数据库中间件(atlas/mycat) 的架构来优化.

我的环境:

centos6.5 64位

lnmp1.3一键环境包

CentOS6.4 X64 安装sphinx及sphinx for php扩展

安装前请先确定安装了常用的组件,然后在官方网站下载最新的sphinx,

yum install -y python python-devel

http://sphinxsearch.com/downloads/release/

安装sphinx

tar zxvf sphinx-2.2.10-release.tar.gz
cd sphinx-2.2.10-release
./configure --prefix=/usr/local/sphinx –-with-mysql
make && make install

在make时如果出现undefined reference to libiconv的错,请参考 http://www.lvtao.net/database/sphinx-make-error.html 解决方法
libsphinxclient 安装(PHP模块需要)

cd api/libsphinxclient
./configure –prefix=/usr/local/sphinx
make && make install

安装PHP的Sphinx模块
下载地址:http://pecl.php.net/package/sphinx

wget http://pecl.php.net/get/sphinx-1.3.0.tgz
tar zxf sphinx-1.3.3.tgz
cd sphinx-1.3.3
/usr/local/php/bin/phpize
./configure --with-php-config=/usr/local/php/bin/php-config --with-sphinx=/usr/local/sphinx/
make && make install 添加php扩展库
查看php.ini位置
php --ini

编辑配置
vi /usr/local/php/etc/php.ini
:$ 跳至文件尾部

extension_dir="/usr/local/php/lib/php/extensions/no-debug-non-zts-20131226/"
[sphinx]
extension=sphinx.so

php -m 或者 phpinfo() 查看是否已经加载扩展

首先我们得在服务器端把索引建立好,以便php通过端口访问获取

复制默认配置文件,重新创建一个配置文件

cp /usr/local/sphinx/etc/sphinx-min.conf.dist  /usr/local/sphinx/etc/sphinx.conf

sphinx.conf.dist是完整版默认配置,有很多内容,我这里选择复制的是sphinx-min.conf.dist迷你版,只要满足基本查询需要即可

#
# Minimal Sphinx configuration sample (clean, simple, functional)
# source src1
{
type = mysql sql_host = localhost
sql_user = root
sql_pass = root
sql_db = allchips_test
sql_port = 3306 # optional, default is 3306 sql_query = select * from products #sql_attr_uint = id
#sql_attr_timestamp = date_added sql_field_string = product_id
sql_field_string = partNo
} source src2
{
type = mysql sql_host = localhost
sql_user = root
sql_pass = root
sql_db = allchips_test
sql_port = 3306 # optional, default is 3306 sql_query = select * from product_prices } source src3
{
type = mysql sql_host = localhost
sql_user = root
sql_pass = root
sql_db = allchips_test
sql_port = 3306 # optional, default is 3306 sql_query = select * from product_attrs } index products
{
source = src1
path = /mnt/data/products
min_infix_len = 1
infix_fields = partNo,short_desc } index prices
{
source = src2
path = /mnt/data/prices } index attrs
{
source = src3
path = /mnt/data/attrs } indexer
{
mem_limit = 128M
} searchd
{
listen = 9312
listen = 9306:mysql41
log = /mnt/data/log/searchd.log
query_log = /mnt/data/log/query.log
read_timeout = 5
max_children = 30
pid_file = /mnt/data/log/searchd.pid
seamless_rotate = 1
preopen_indexes = 1
unlink_old = 1
workers = threads # for RT to work
binlog_path = /mnt/data
}

  

最下面的indexer和searchd分别是索引创建,和查询命令的配置,基本只要设置好自己想要日志路径即可

重要的上面的部分,source (来源) 和 index (索引)

分析一下我的需求,我的产品搜索主要3张表

产品表products, (id,product_id)

产品价格表product_prices,

产品参数表product_attrs

三者以产品表的product_id关联1对多

source src1 对应  index products

source src2 对应  index prices

source src3 对应  index attrs

在source中是可以设置自定义返回的字段的

如上面的
sql_field_string = product_id
sql_field_string = partNo

配置好了之后,创建索引

在使用  /usr/local/sphinx/bin/indexer -c /usr/local/sphinx/etc/sphinx.conf  --all --rotate 命令的的时候,如果searchd进程没有在监听,执行了更新,会出现no rotate的提示。

如果不想全部生成你可以不用--all,分开多个源生成也可以

/usr/local/sphinx/bin/indexer -c /usr/local/sphinx/etc/sphinx.conf  products

/usr/local/sphinx/bin/indexer -c /usr/local/sphinx/etc/sphinx.conf  prices

/usr/local/sphinx/bin/indexer -c /usr/local/sphinx/etc/sphinx.conf  attrs

如果没有什么问题一般是这样的。

接下来要用searchd作为sphinx在服务器的守护进程

/usr/local/sphinx/bin/searchd -c /usr/local/sphinx/etc/sphinx.conf(途中的test.conf是以前测试的,使用sphinx.conf即可)

一般如果报错

文件夹不存在,则创建文件夹

如果已经端口进程已经在运行,那么有2种方法停止

1,/usr/local/sphinx/bin/searchd -c /usr/local/sphinx/etc/sphinx.conf --stop

2, netstat -tnl 查看端口9312是否在监听

lsof -i:9312  查看9312端口信息,获得pid

kill {pid}

杀掉进程之后重新执行searchd命令启动

==========

php端

<?php
//index.php
phpinfo();die;
$s = new SphinxClient;
$s->setServer("127.0.0.1", 9312); $s->setMatchMode(SPH_MATCH_PHRASE);
  
  

  

//$s->setSortMode(SPH_SORT_ATTR_DESC,'is_tuan'); //指定模式
$s->setSortMode(SPH_SORT_EXTENDED,'is_tuan desc'); //扩展模式

$s->SetFilterString('status','1'); //这个字段 需要在 sql_attr_string 中设置显示,不然找不到字段  如果设置的是sql_attr_uint就是int ,后面是类型

    $s->setMaxQueryTime(30);

    $res1 = $s->query('usb','products');
$res2 = $s->query('53e6dde17a667c4b2af1d38ba0a466c4','prices');
$res3 = $s->query('53e6dde17a667c4b2af1d38ba0a466c4','attrs'); //$res = $s->query('开关','products');
//$res = $s->query('products'); $err = $s->GetLastError();
//var_dump(array_keys($res['matches']));
// echo "<br>"."通过获取的ID来读取数据库中的值即可。"."<br>"; echo '<pre>'; $products=!empty($res1['matches'])?$res1['matches']:"";
$prices=!empty($res2['matches'])?$res2['matches']:"";
$attrs=!empty($res3['matches'])?$res3['matches']:""; print_r($products);
print_r($prices);
print_r($attrs); if(!empty($err)){
print_r($err);
} $s->close();

coreseek的官网挂了下载不了,所以暂时不弄中文。以后看有时间在下载个中文词典打进去

这是打印的query返回的matches匹配结果,如果要查看整个query结果,可以看PHP手册http://php.net/manual/zh/sphinxclient.query.php

返回数据结构
值说明
"matches" 存储文档ID以及其对应的另一个包含文档权重和属性值的hash表
"total" 此查询在服务器检索所得的匹配文档总数(即服务器端结果集的大小,且与相关设置有关)
"total_found" (服务器上找到和处理了的)索引中匹配文档的总数
"words" 将查询关键字(关键字已经过大小写转换,取词干和其他处理)映射到一个包含关于关键字的统计数据(“docs”——在多少文档中出现,“hits”——共出现了多少次)的小hash表上。
"error" searchd报告的错误信息
"warning" searchd报告的警告信息

上面的配置默认监听了,9312和9306端口,9312是给php程序链接的,9306是本地数据库调试端口,如果想要在服务器做测试,可以试试链接

mysql -h127.0.0.1 -P9306

products是索引名index,match是规则匹配,

通配符可以在官网手册上 http://sphinxsearch.com/docs/current.html#conf-dict  搜索"wildcards" 
 看到 search (e.g. "t?st*", "run%", "*abc*")
 
我在使用时,发现关键字分词不准确,比如 完整产品信号 PSMN1R1-25YLC,115 
 
PSMN1R1-25YLC,115   true
PSMN1R1-25YLC,11   false
PSMN1R1-25YLC,1   false
PSMN1R1-25YLC,   true
PSMN1R1-25YLC  true
 
由此可以判断,应该是字符分词长度设置有问题,解决如下
source中
sql_query_pre = SET NAMES utf8    #sql执行前,会执行,为了保证不是字符集的问题
index中
min_prefix_len = 1    #设置最小索引前缀长度1
 
php中:
use sngrl\SphinxSearch\SphinxSearch;

class TestController extends Controller
{ public function index(Request $request)
{ $sphinx = new SphinxSearch();
$sphinx->setMatchMode(\Sphinx\SphinxClient::SPH_MATCH_PHRASE);
$results = $sphinx->search("%PSMN1R1-25YLC,11*", 'products')->query();
$error=$sphinx->getErrorMessage();
$products=!empty($results['matches']) ? $results['matches'] : array();
echo '<pre>';
print_r($products); //dd($results); //dd($error); }
}

匹配成功。

 
 
 
使用中会遇到的问题:
1,索引更新,可以使用rt增量索引来记录变化的记录id
2,定时更新索引
如果searchd进程正在运行,你除了可以kill掉他的进程外,还可以执行--rotate 参数进行 无缝更新,无需重启服务
/usr/local/sphinx/bin/indexer -c /usr/local/sphinx/etc/sphinx.conf  products --rotate
你可以把这个命令 写入crontab任务中,定时执行,在laravel中你可以在程序中自定义。

================================================================

Atlas听说很多人都在用,安装测试中 待续 -


sphinx全文检索 安装配置和使用的更多相关文章

  1. 搭建coreseek(sphinx+mmseg3)详细安装配置+php之sphinx扩展安装+php调用示例(转)

    一个文档包含了安装.增量备份.扩展.api调用示例,省去了查找大量文章的时间. 搭建coreseek(sphinx+mmseg3)安装 [第一步] 先安装mmseg3 cd /var/install ...

  2. sphinx全文检索功能 | windows下测试 (一)

    前一阵子尝试使用了一下Sphinx,一个能够被各种语言(PHP/Python/Ruby/etc)方便调用的全文检索系统.网上的资料大多是在linux环境下的安装使用,当然,作为生产环境很有必要部署在* ...

  3. Sphinx(coreseek) 安装使用以及词库的扩展

    1.Sphinx(coreseek) 是啥 一般而言,Sphinx是一个独立的全文搜索引擎:而Coreseek是一个支持中文的全文搜索引擎,意图为其他应用提供高速.低空间占用.高结果相关度的中文全文搜 ...

  4. Sphinx全文索引安装教程

    首先了解一下sphinx全文索引的相关知识官方网站:http://www.sphinxsearch.com/ 官方文档:http://www.sphinxsearch.com/docs/ 中文支持:h ...

  5. discuz sphinx全文检索搜索引擎方案

    基于discuz的索引配置文件,这个配置文件比较灵活,可以根据不同的需求来配置 # # linuxTone full index search configure file # source lt_p ...

  6. Sphinx学习之sphinx的安装篇

    一.  Sphinx简介 Sphinx是由俄罗斯人Andrew Aksyonoff开发的一个全文检索引擎.意图为其他应用提供高速.低空间占用.高结果 相关度的全文搜索功能.Sphinx可以非常容易的与 ...

  7. Coreseek/sphinx全文检索的了解

    Coreseek/sphinx全文检索的了解 概述: 全文检索是一种将文件里全部文本与检索项匹配的文字资料检索方法,全文检索是将存储于数据库中整本书.整篇文章中的随意内容信息查找出来的检索.它能够依据 ...

  8. sphinx的安装

    1.下载sphinx 没想到sphinx3解压后即可: wget http://sphinxsearch.com/files/sphinx-3.0.2-2592786-linux-amd64.tar. ...

  9. elasticsearch系列一:elasticsearch(ES简介、安装&配置、集成Ikanalyzer)

    一.ES简介 1. ES是什么? Elasticsearch 是一个开源的搜索引擎,建立在全文搜索引擎库 Apache Lucene 基础之上 用 Java 编写的,它的内部使用 Lucene 做索引 ...

随机推荐

  1. N久没写过东西了..写个最近在研究的程序

    import numpy as np import matplotlib.pyplot as plt #a = np.matrix([[1,1.15],[1,1.9],[1,3.06],[1,4.66 ...

  2. 二十一、Java基础--------IO流之综合案例分析

    前三篇文章详细介绍了IO流体系所涉及的重点内容,为了帮助理解与学习,本片博客主要是分析一个与IO操作相关的题目. 例1:在我们观看视频时经常要关注的就是视频的时间长度,在学习了IO操作之后,就可以自己 ...

  3. UICollectionView 自定义组头组尾的XIB方法

    UICollectionView的加载方式和Tableview很像,基本上加载的方法都差不多,尤其是它的数据源的方法和代理方法基本上类似,只不过是名字上有点细微的差别而已.这里面不赘述. 1. UIC ...

  4. Masonry 创建Button的简单使用

    代码创建控制器,控件在实际开发中很实用,方便快捷,而Masonry第三方框架更是将代码创建效率提高了很多! 如何代码创建?如何使用第三方框架? 1.首先删除系统自带的SB,详见下图 2.在AppDel ...

  5. Oracle Partition By 的使用

    1.概述 Parttion by 关键字是Oracle中分析性函数的一部分,它和聚合函数不同的地方在于它能够返回一个分组中的多条记录,儿聚合函数一般只有一条反映统计值的结果. 2.使用方式 场景:查询 ...

  6. 用shell脚本监控进程是否存在 不存在则启动的实例

    用shell脚本监控进程是否存在 不存在则启动的实例,先上代码干货: #!/bin/shps -fe|grep processString |grep -v grepif [ $? -ne 0 ]th ...

  7. sqllite 默认当前日期写法

    create table IF NOT EXISTS realpoint(_id integer primary key autoincrement,rountId varchar(50),lng d ...

  8. IOS 创建渐变图层

    代码如下 typedef enum { GradientLayerKindLeftRight = , GradientLayerKindUpDown, GradientLayerKindLBRT,// ...

  9. ajax动态添加的li不能绑定click事件

    单纯的给li标签添加click事件,是不会执行的. 经过试验 <ul id="searchedUser"><li>搜索结果</li></u ...

  10. knockoutjs(二)

    Observables(监控属性)Knockout是在下面三个核心功能是建立起来的: 1监控属性(Observables)和依赖跟踪(Dependency tracking) 2声明式绑定(Decla ...