zoukankan      html  css  js  c++  java
  • sphinx全文检索 安装配置和使用

    公司项目刚刚导入大量产品数据,然后发现网站的产品搜索很卡,原本是原生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 sngrlSphinxSearchSphinxSearch;
    
    class TestController extends Controller
    {
    
        public function index(Request $request)
        {    
    
                
            $sphinx = new SphinxSearch();
            $sphinx->setMatchMode(SphinxSphinxClient::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听说很多人都在用,安装测试中 待续 -




  • 相关阅读:
    jvm基本结构和解析
    多态的意思
    java中对象的简单解读
    double类型和int类型的区别
    python 解析xml文件
    win10不能映射Ubuntu共享文件
    Qt程序打包
    Ubuntu boot分区文件误删,系统无法启动,怎么解
    ubuntu Boot空间不够问题“The volume boot has only 5.1MB disk space remaining”
    Ubuntu 分辨率更改 xrandr Failed to get size of gamma for output default
  • 原文地址:https://www.cnblogs.com/findgor/p/5644540.html
Copyright © 2011-2022 走看看