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

    https://www.cnblogs.com/findgor/p/5644540.html

    公司项目刚刚导入大量产品数据,然后发现网站的产品搜索很卡,原本是原生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迷你版,只要满足基本查询需要即可

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    #
    # 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听说很多人都在用,安装测试中 待续 -

  • 相关阅读:
    windows端口占用处理方法
    【接口】接口测试常见响应码类型(二)
    【接口】SpringBoot+接口开发(一)
    【java+selenium3】Tesseract-OCR识别图片验证码 (十六)
    java读写Txt文件
    【java+selenium3】自动化基础小结+selenium原理揭秘 (十七)
    【java+selenium3】自动化cookie操作+图形验证码处理 (十五)
    【java+selenium3】自动化截图 (十四)
    【Java+selenium3】 Firefox/ IE/ Chrome主流浏览器自动化环境搭建(一)
    【java+selenium3】自动化处理文件上传 (十三)
  • 原文地址:https://www.cnblogs.com/lxwphp/p/15454417.html
Copyright © 2011-2022 走看看