`

sphinx 多个表查询

阅读更多
<!-- 正文 -->

sql_query = SELECT `id`, 2 AS table_id, `username`, `password`, `email`, `salt`, `from` FROM table_2

  1. ["matches"]=>
  2. array(16) {
  3. [0]=>
  4. array(3) {
  5. ["id"]=>
  6. string(2) "68"
  7. ["weight"]=>
  8. string(1) "2"
  9. ["attrs"]=>
  10. array(1) {
  11. ["table_id"]=>
  12. string(1) "2"

 

好吧,我又无聊了 Orz

之前搭建的裤子库是单表的,建索引的时候也没考虑什么后续扩展,有小伙伴表示要玩多表查询,于是研究了下……

为嘛不用增量索引呢?本来一个表就10G多够大了,而且增量索引还得不时添加&合并索引……只是本机搭着玩玩,还是算了吧。

翻到一篇文章,里面说到了配置文件里的继承和重载,对于添加多个数据源还是挺有帮助的,摘抄下:

定义父类email

source email { 
    ....
}

定义子类subemail继承email类的所有设置:

source subemail : email { #除了source,index也可以使用继承
    ....
}

子类中可以重载email中的设置

source subemail : email {
    sql_host      = www.ibos.com.cn    #重载主机
    sql_query    = SELECT * FROM subemail    #重载sql_query语句
}

其实继承很少被使用到,但有一个很实用的例子就是有很多数据源使用同一数据库的时候,继承就派上用场了

source setdb {     #setdb类只实现连接数据库
    sql_host                  =     localhost
    sql_user                  =     root
    sql_pass                  =     root
    sql_db                     =     ibos
    sql_port                   =     3306
}

souce email : setdb{    #继承setdb类
    sql_query = ...        #直接写查询语句,而不用再写数据库信息
}

souce diary : setdb {
    sql_query = ...  
}
 
souce article : setdb {
    sql_query = ...  
}

souce forum : setdb {
    sql_query = ...  
}

然后我在上一次的配置文件基础上改了改,加上了另一个表做数据源。
但是在改 php 文件时发现个问题:之前的源码里用的是 $sql = "select * from table_1 where id in($ids)" ,现在加了另一个表以后就不好搞了。

因为两个表的 ID 字段都是从 1 开始自增的,如果用多表 Union 的话可能把两个表中的同一个 ID 的行取出来。有个解决办法就是把第二个表 ID 的自增起始数值改成第一个表 ID 的结束数值—— 不过这个方法只适用极少的情况……

接着百度了很久无果,谷歌也搜不到…… 后来把搜索关键词换为 coreseek indexes in different tables 就搜到一大堆了 Orz

根据这个 Using Sphinx with PHP with multiple indexes 的回答,把配置文件重新改了下:

#源定义
source table_1
{
    type                    = mysql

    sql_host                = localhost
    sql_user                = test
    sql_pass                = test
    sql_db                    = sed
    sql_port                = 3306
    sql_query_pre            = SET NAMES utf8

    sql_query                = SELECT `id`, 1 AS table_id, `username`, `password`, `email`, `salt`, `from` FROM table_1
    sql_attr_uint            = table_id         #从SQL读取到的值必须为整数
    #sql_attr_timestamp        = date_added  #从SQL读取到的值必须为整数,作为时间属性

    sql_query_info_pre      = SET NAMES utf8                                        #命令行查询时,设置正确的字符集
    sql_query_info            = SELECT * WHERE ID=$id #命令行查询时,从数据库读取原始数据信息
}

source table_2 : table_1
{
    sql_query = SELECT `id`, 2 AS table_id, `username`, `password`, `email`, `salt`, `from` FROM table_2
}

#index定义
index table_1
{
    source            = table_1    #对应的source名称
    path            = E:/SQL_DATA/coreseek/var/data/table_1 #请修改为实际使用的绝对路径,例如:/usr/local/coreseek/var/...
    docinfo            = extern
    mlock            = 0
    morphology        = none
    min_word_len        = 1
    ondisk_dict     = 1
    html_strip                = 0

    #中文分词配置,详情请查看:http://www.coreseek.cn/products-install/coreseek_mmseg/
    #charset_dictpath = /usr/local/mmseg3/etc/ #BSD、Linux环境下设置,/符号结尾
    charset_dictpath = E:/SQL_DATA/coreseek/etc/ #Windows环境下设置,/符号结尾,最好给出绝对路径,例如:C:/usr/local/coreseek/etc/...
    charset_type        = zh_cn.utf-8
}

index table_2 : table_1
{
    source = table_2
    path =  E:/SQL_DATA/coreseek/var/data/table_2
}

#全局index定义
indexer
{
    mem_limit            = 1024M
}

#searchd服务定义
searchd
{
    listen                  =   9000
    read_timeout        = 5
    max_children        = 30
    max_matches            = 1000
    seamless_rotate        = 0
    preopen_indexes        = 0
    unlink_old            = 1
    pid_file = E:/SQL_DATA/coreseek/var/log/searchd_mysql.pid  #请修改为实际使用的绝对路径,例如:/usr/local/coreseek/var/...
    log = E:/SQL_DATA/coreseek/var/log/searchd_mysql.log        #请修改为实际使用的绝对路径,例如:/usr/local/coreseek/var/...
    query_log = E:/SQL_DATA/coreseek/var/log/query_mysql.log #请修改为实际使用的绝对路径,例如:/usr/local/coreseek/var/...
    binlog_path =                                #关闭binlog日志
}

所以给返回的 matches 加个 table_id 的属性就好了,建好索引后查询时 matches 返回值类似这样:

["matches"]=>
  array(16) {
    [0]=>
    array(3) {
      ["id"]=>
      string(2) "68"
      ["weight"]=>
      string(1) "2"
      ["attrs"]=>
      array(1) {
        ["table_id"]=>
        string(1) "2"
      }
    }
    [1]=>
    array(3) {
      ["id"]=>
      string(3) "350"
      ["weight"]=>
      string(1) "2"
      ["attrs"]=>
      array(1) {
        ["table_id"]=>
        string(1) "1"
      }
    }

需要注意的是如果之前有把 searchd 注册成服务的话要记得换个端口……

最后改一下用于搜索的 PHP 文件(渣代码勿怪…):

<?php
// 引用sphinxapi类
require "sphinxapi.php";
//关闭错误提示
error_reporting(E_ALL & ~E_NOTICE);
$num = 0;
if (!empty($_GET) && !empty($_GET['q'])) {
    $Keywords = strip_tags(trim($_GET['q']));
    if (!empty($_GET['m']) && 1 == $_GET['m']) {
        $Keywords = substr(md5($Keywords), 8, 16);
    }
    if (!empty($_GET['m']) && 2 == $_GET['m']) {
        $Keywords = md5($Keywords);
    }
    $cl = new SphinxClient();
    // 返回结果设置
    $cl->SetServer('127.0.0.1', 9000);
    $cl->SetConnectTimeout(3);
    $cl->SetArrayResult(true);
    // 设置是否全文匹配
    if (!empty($_GET) && !empty($_GET['f'])) {
        $cl->SetMatchMode(SPH_MATCH_ALL);
    } else {
        $cl->SetMatchMode(SPH_MATCH_ANY);
    }
    if (!empty($_GET) && !empty($_GET['p'])) {
        $p = !intval(trim($_GET['p'])) == 0 ? intval(trim($_GET['p'])) - 1 : 0;
        $p = $p * 20;
        // 我在sed.conf 设置了最大返回结果数1000。但是我在生成页码的时候最多生成20页,我想能满足大部分搜索需求了。
        // 以下语句表示从P参数偏移开始每次返回20条。
        $cl->setLimits($p, 20);
    } else {
        $cl->setLimits(0, 20);
    }
    $res = $cl->Query("$Keywords", "*");
    //var_dump($res);
    @mysql_connect("localhost", "test", "test"); //数据库账号密码
    mysql_select_db("sed"); //数据库库名名
    mysql_query("set names utf8");

    $tables = ['table_1', 'table_2'];  //把表名放入数组
    function getResult($id, $table)
    {
            $sql    = "select * from {$table} where id = " . $id;
            $result = mysql_query($sql);
            while ($row = mysql_fetch_array($result)) {
                echo "<tr><td>" . $row['username'] . "</td>";
                echo "<td>" . $row['email'] . "</td>";
                echo "<td>" . $row['password'] . "</td>";
                echo "<td>" . $row['salt'] . "</td>";
                echo "<td>" . $row['from'] . "</td></tr>";
            }
    }

    if ($res["total_found"]) {
        $num = $res["total_found"];
    } else {
        $num = 0;
    }
}
?>
<!DOCTYPE html>
<html>
<head>
   <title>The Web of Answers</title>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-with,initial-scal=1">
   <link href="css/bootstrap.min.css" rel="stylesheet">
   <script src="js/jquery.js"></script>
   <script src="js/bootstrap.min.js"></script>
   <script>
    function check(form){
        if(form.q.value==""){
          alert("Not null !");
          form.q.focus();
          return false;
        }
    }
    </script>
   <style>
        h1 {
            font-family: Times New Roman, Lucida Handwriting;
        }
        body {
            background-image: url(img/bg.jpg);
        }
   </style>
</head>
<body>
    <div class="container" id="container">
        <div id="page-header">
            <h1 class="text-center"> The Web of Answers </h1>
        </div>
        <div class="row">
        <form action="" method="get" class="form-horizontal" role="form">
            <div id="checkbox" class="col-md-6 col-md-offset-3">
                <label class="checkbox-inline">
                    <input type="checkbox" id="full" name="f" value="1">   完整匹配
                </label>
                <label class="checkbox-inline">
                      <input type="checkbox" id="md5_16" name="m" value="1">
                       MD5匹配(16位)
                </label>
                <label class="checkbox-inline">
                      <input type="checkbox" id="md5_32" name="m" value="2">
                       MD5匹配(32位)
                </label>
            </div>
            <div class="input-group col-md-6 col-md-offset-3">
                <input type="text" class="form-control" name="q" placeholder="请输入" value="<?php echo strip_tags(trim($_GET['q']));?>">
                    <div class="input-group-btn">
                        <button type="submit" class="btn btn-primary" onclick="check(form)">Search</button>
                    </div>
             </div>
        </form>
    </div>
    <br>
<?php
if (0 != $num) {
    echo "<div class=\"row\">
    <div class=\"alert alert-success alert-dismissible col-md-10 col-md-offset-1\" role=\"alert\">
    <button type=\"button\" class=\"close\" data-dismiss=\"alert\"><span aria-hidden=\"true\">&times;</span><span class=\"sr-only\">Close</span></button>
    找到与<b>&nbsp{$Keywords}&nbsp</b>相关的结果 {$num} 个。用时 {$res['time']} 秒。</div>";
    echo "<div class=\"table-responsive col-md-10 col-md-offset-1\">
        <table class=\"table table-striped table-hover\">
          <tr>
          <th>Username</th>
          <th>Email</th>
          <th>Password</th>
          <th>Salt</th>
          <th>From</th>
          </tr>";
    if (is_array($res["matches"])) {
        foreach ($res["matches"] as $docinfo) {
            $table_id = $docinfo['attrs']['table_id'];
            getResult($docinfo['id'], $tables[$table_id - 1]);
            }
    }
    echo "</table></div></div>";
    } else {
        if (!empty($_GET) && !empty($_GET['q'])) {
            echo "<div class=\"alert alert-warning alert-dismissible col-md-10 col-md-offset-1\" role=\"alert\">
                <button type=\"button\" class=\"close\" data-dismiss=\"alert\"><span aria-hidden=\"true\">&times;</span><span class=\"sr-only\">Close</span></button>
                找不到与<b>&nbsp{$Keywords}&nbsp</b>相关的结果。请更换其他关键词试试。</div></div>";
        }
}
?>
    <div id="pages">
    <center>
        <nav>
            <ul class="pagination">
<?php
if ($num !== 0) {
    $pagecount = (int) ($num / 20);
    if (!($num % 20) == 0) {
        $pagecount = $pagecount + 1;
    }
    if ($pagecount > 20) {
        $pagecount = 20;
    }
    $highlightid = !intval(trim($_GET['p'])) == 0 ? intval(trim($_GET['p'])) : 1;
    for ($i = 1; $i <= $pagecount; $i++) {
        if ($highlightid == $i) {
            echo "<li class=\"active\"><a href=\"#\">{$i}<span class=\"sr-only\">(current)</span></a></li>";
        } else {
            echo "<li><a href=\"index.php?q={$Keywords}&p={$i}\">{$i}</a></li>";
        }
    }
}
?>
            </ul>
        </nav>
    </center>
    </div>
    <div id="footer">
        <p class="text-center">
            The Web of Answers &copy;2010-2015 | Powered by b0rg
        </p>
    </div>
    </div>
</body>
</html>

参考资料:

<!-- 版权 -->
分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    用PYTHON多线程处理Sphinx遇到的问题

    在多线程环境下使用Sphinx,目标是通过并行处理多个文档来加速构建过程。Python的`threading`模块提供了创建和管理线程的基础功能。我们可以通过创建一个线程池,将每个文档的构建任务分发到不同的线程中去。 首先...

    java 整合 sphinx

    Sphinx的核心特性包括:全文索引、布尔操作符、短语匹配、近似搜索、同义词处理、过滤器(如范围查询、多值字段)等。 2. **Java整合Sphinx**: 在Java应用中使用Sphinx,首先需要引入Sphinx的Java客户端库,例如`...

    数据库 搜索引擎 sphinx

    6. **排序和过滤**: Sphinx允许根据多个字段进行排序,并可以设置过滤条件,例如限制搜索结果的日期范围、价格区间等,帮助用户更精确地找到所需信息。 7. **分布式搜索**: 对于大规模的数据,Sphinx支持分布式搜索...

    Sphinx-JAVA接口

    8. **分布式搜索**: 如果Sphinx部署在多台服务器上,JAVAAPI能处理分布式搜索,将查询分散到各个节点并合并结果。 **应用场景** 1. **内容搜索**: 在内容管理系统、博客平台、电子商务网站等中,Sphinx JAVAAPI...

    sphinx3-0.4.1.rar_Sphinx3_c 语音识别

    sphinx系统是一个拥有悠久历史的语音识别系统,李开复自称第一个sphinx是他写的。 传说 中是第一个实用的10数字语音系统。 是由卡奈基.美隆大学研发。 sphinx3.x是基于C语言的最新版本,sphinx和 sphinx2请大家...

    Sphinx-完整中文手册

    在Sphinx的使用过程中,用户会遇到各种问题,因此文档中还提供了搜索数据查询方法以及一些附加方法,比如Query和AddQuery,供用户进行批量查询或特定条件下的查询。这些方法的使用使得Sphinx在处理复杂查询时更加...

    sphinx支持discuz包

    5. **扩展性**:Sphinx 具有良好的扩展性,可以通过设置多个索引,分别对应不同类型的论坛数据,如主题、帖子、用户资料等。 6. **多语言支持**:除了中文,Sphinx 还支持其他多种语言的全文检索,满足国际化社区的...

    语音识别 sphinx4 JAVA 教程

    Sphinx-4是卡内基梅隆大学(CMU)开发的一个开源语音识别引擎,特别适合Java开发者使用。它提供了丰富的API和工具,支持实时语音识别,具有良好的可扩展性和灵活性。 【Sphinx-4的Java环境搭建】 在Java环境下使用...

    php7的sphinx扩展,适用linux,mac

    CoreSeek是Sphinx在中国的一个分支项目,它包含了更多的中文分词支持,尤其适合处理中文文本的全文检索。在安装PHP7的Sphinx扩展时,如果需要处理中文数据,可能需要集成CoreSeek的源码。这样做的目的是为了确保...

    CoreSeek/Sphinx中文手册

    Sphinx的安装过程涉及多个方面,包括选择支持的操作系统、安装必要的工具、配置环境变量、以及如何在不同的操作系统(如Linux、BSD、Windows)上安装。安装过程中可能会遇到一些问题,文档中也提供了一些已知问题的...

    sphinx中文语音训练手册

    发音字典告诉sphinx每个字的标准读音,但面对的说话人往往不会以标准读音来朗读。 因此sphinx需要学习说话人的“口音”。 如果训练时的读者发音比较标准,则sphinx能“举一反三”,识别其他不那么标准的读者的语音。...

    sphinx+mysql 安装手册

    1. **分布式搜索**:通过设置多个索引和分布式搜索节点,实现更大规模的数据检索。 2. **近实时搜索**:利用Sphinx的实时索引功能,实现在数据插入后短时间内即可搜索到新数据。 3. **多语言支持**:配置Sphinx支持...

    pocketsphinx语音库

    3. **多平台支持**:Pocketsphinx支持多种操作系统,包括Linux、Windows、Mac OS X以及Android和iOS。 4. **可定制化**:用户可以根据自己的需求训练自定义的声学模型和语言模型,适应特定领域或方言的识别。 ### ...

    php7 sphinx扩展

    3. 分布式搜索:Sphinx支持分布式索引,通过配置文件设置多个数据源,`setLimits()`可限制每个数据源的返回结果。 四、异常处理与调试 PHP7 Sphinx扩展支持异常处理,当查询失败时会抛出异常。你可以使用try-catch...

    PHP 全文检索引擎 Sphinx 介绍

    6. **多种查询类型**:支持布尔查询、短语查询、近义词查询,以及每个文档的多个全文检索域(默认最多32个)。 7. **多属性支持**:每个文档可以拥有多个属性,这些属性可用于过滤和排序搜索结果,提供了更精细的...

    Windows下安装使用Sphinx

    5. **支持分布式搜索**:能够跨多个服务器进行搜索。 6. **文档摘要生成**:自动提取文档的关键部分作为摘要。 7. **从 MySQL 内部的插件式存储引擎上搜索**:集成 MySQL 数据库,提高搜索性能。 8. **布尔、短语和...

    sphinx安装包,不错的东西

    7. **排序和过滤**:Sphinx允许根据多个字段进行排序,并可以设置过滤条件,比如按时间、评分等进行排序,或只显示满足特定条件的文档。 8. **词性标注和同义词处理**:Sphinx可以处理词性标注,提高搜索的准确性。...

    sphinx2.20

    为了提高搜索性能,可以使用分布式索引,将大型数据集分布在多个服务器上。 在实际应用中,还需要对搜索结果进行优化,例如通过调整查询语法、设置排名算法、添加相关性评分等。同时,为了提供友好的用户体验,可以...

Global site tag (gtag.js) - Google Analytics