PHP使用 Sphinx 索引内…

集成 Sphinx 软件

http://www.ibm.com/developerworks/cn/opensource/os-php-sphinxsearch/

要应用 Sphinx 来解决问题,您必须定义一个或多个数据源以及一个或多个索引。

source 将标识数据库来建立索引,提供验证信息,并且定义查询用以构造每行。数据源可以随意地标识一列或多列作为过滤器,Sphinx 将之称为。您将使用组来过滤结果。例如,单词描述可能得到 900 个匹配。如果只对特定型号的汽车匹配感兴趣,则可以进一步使用型号组进行过滤。

index 将要求获得数据源(即一组数据行)并定义应当如何为已从数据源中提取出来的数据编目。

您将在 sphinx.conf 文件中定义数据源和索引。Body Parts 的数据源是 MySQL 数据库。清单 5 显示了名为 catalog 的数据源的部分定义 —— 指定连接的数据库以及如何建立连接(主机、套接字、用户和密码)的代码片段。

清单 5. 用于访问 MySQL 数据库的设置
source catalog 
{
    type                            = mysql
    
    sql_host                        = localhost
    sql_user                        = reaper
    sql_pass                        = s3cr3t
    sql_db                          = body_parts
    sql_sock                        =  /var/run/mysqld/mysqld.sock
    sql_port                        = 3306

接下来,创建一个查询以生成要被索引的行。通常,将创建 SELECT 子句,可能需要把许多表 JOIN 在一起才能得到行。但这里存在一个问题:搜索型号和年份必须使用 Assembly 表,但是零件号和零件描述只能在 Inventory 表中找到。为此,Sphinx 必须能够把搜索结果与 32 位整型主键绑定在一起。

要获得右侧表单中的数据,需要创建一个视图 —— MySQL V5 中的新结构,它将把来自其他表的列整合到单独的合成虚拟表中。使用视图,各类搜索所需的所有数据都在一个位置,但是活动数据实际上存在于其他表中。清单 6 显示了定义 Catalog 视图的 SQL。

清单 6. Catalog 视图将把数据整合到虚拟表中
CREATE OR REPLACE VIEW Catalog AS
SELECT
  Inventory.id,
  Inventory.partno,
  Inventory.description,
  Assembly.id AS assembly,
  Model.id AS model
FROM
  Assembly, Inventory, Model, Schematic
WHERE
  Schematic.partno_id=Inventory.id 
  AND Schematic.model_id=Model.id 
  AND Schematic.assembly_id=Assembly.id;

如果用前面所示的表和数据创建名为 body_parts 的数据库,则 Catalog 视图应当类似以下内容:

mysql> use body_parts;
Database changed
mysql> select * from Catalog;
+----+---------+---------------------+----------+-------+
| id | partno  | description         | assembly | model |
+----+---------+---------------------+----------+-------+
|  6 | 765432  | Bolt                |        5 |     1 | 
|  8 | ENG088  | Cylinder head       |        5 |     1 | 
|  1 | WIN408  | Portal window       |        3 |     1 | 
|  5 | WIN958  | Windshield, front   |        3 |     1 | 
|  4 | ACC5409 | Cigarette lighter   |        7 |     3 | 
|  9 | ENG976  | Large cylinder head |        5 |     3 | 
|  8 | ENG088  | Cylinder head       |        5 |     7 | 
|  6 | 765432  | Bolt                |        5 |     7 | 
+----+---------+---------------------+----------+-------+
8 rows in set (0.00 sec)

在视图中,字段 id 将指回 Inventory 表中的零件条目。partno 和 description 列是要搜索的主要文本,而 assembly 和 model 列用作进一步过滤结果的组。视图就绪后,构造数据源查询就是小事一桩。清单 7 显示了 catalog 数据源定义的其余部分。

清单 7. 查询创建待索引的行
    # indexer query
    # document_id MUST be the very first field
    # document_id MUST be positive (non-zero, non-negative)
    # document_id MUST fit into 32 bits
    # document_id MUST be unique
    sql_query                       = \
            SELECT \
                    id, partno, description, \
                    assembly, model \
            FROM \
                    Catalog;
    
    sql_group_column                = assembly
    sql_group_column                = model
    
    # document info query
    # ONLY used by search utility to display document information
    # MUST be able to fetch document info by its id, therefore
    # MUST contain '$id' macro 
    #
    sql_query_info          = SELECT * FROM Inventory WHERE id=$id
}

sql_query 必须包括后续查找需要使用的主键,并且它必须包括需要索引和用作组的所有字段。两个 sql_group_column 条目将声明 Assembly 和 Model 可用于过滤结果。并且 search 实用程序将使用 sql_query_info 来查找匹配记录。在查询中,$id 被替换为 searchd 返回的每个主键。

最后一个配置步骤是构建索引。清单 8 显示了数据源 catalog 的索引。

清单 8. 描述 catalog 数据源的一个可能的索引
index catalog
{
    source                  = catalog
    path                    = /var/data/sphinx/catalog
    morphology              = stem_en

    min_word_len            = 3
    min_prefix_len          = 0
    min_infix_len           = 3
}

第 1 行将指向 sphinx.conf 文件中的指定数据源。第 2 行将定义存储索引数据的位置;按照约定,Sphinx 索引将被存储到 /var/data/sphinx 中。第 3 行将允许索引使用英文词法。并且第 5 行至第 7 行将告诉索引器只索引含有三个字符或更多字符的那些单词,并且为每个这样的字符的子字符串创建中缀索引(为了便于引用,清单 9 显示了 Body Parts 的完整示例 sphinx.conf 文件)。

清单 9. Body Parts 的示例 sphinx.conf
source catalog
{
    type                            = mysql
    
    sql_host                        = localhost
    sql_user                        = reaper
    sql_pass                        = s3cr3t
    sql_db                          = body_parts
    sql_sock                        =  /var/run/mysqld/mysqld.sock
    sql_port                        = 3306                  

    # indexer query
    # document_id MUST be the very first field
    # document_id MUST be positive (non-zero, non-negative)
    # document_id MUST fit into 32 bits
    # document_id MUST be unique

    sql_query                       = \
            SELECT \
                    id, partno, description, \
                    assembly, model \
            FROM \
                    Catalog;

    sql_group_column                = assembly
    sql_group_column                = model

    # document info query
    # ONLY used by search utility to display document information
    # MUST be able to fetch document info by its id, therefore
    # MUST contain '$id' macro 
    #

    sql_query_info          = SELECT * FROM Inventory WHERE id=$id
}

index catalog
{
    source                  = catalog
    path                    = /var/data/sphinx/catalog
    morphology              = stem_en

    min_word_len            = 3
    min_prefix_len          = 0
    min_infix_len           = 3
}

searchd
{
        port                            = 3312
        log                                     = /var/log/searchd/searchd.log
        query_log                       = /var/log/searchd/query.log
        pid_file                        = /var/log/searchd/searchd.pid
}

底部的 searchd 部分将配置 searchd 守护程序本身。该部分中的条目不言自明。query.log 尤为有用:它将在运行时显示每次搜索并显示结果,例如搜索的文档数和匹配总数。

回页首

构建和测试索引

您现在已经准备好为 Body Parts 应用程序构建索引。为此,需要执行以下步骤:

  1. 键入 $ sudo mkdir -p /var/data/sphinx 创建目录结构 /var/data/sphinx
  2. 假定 MySQL 正在运行,使用如下所示的代码运行索引器来创建索引。
    清单 10. 创建索引
    $ sudo /usr/local/bin/indexer --config /usr/local/etc/sphinx.conf --all
    Sphinx 0.9.7
    Copyright (c) 2001-2007, Andrew Aksyonoff
    
    using config file '/usr/local/etc/sphinx.conf'...
    indexing index 'catalog'...
    collected 8 docs, 0.0 MB
    sorted 0.0 Mhits, 82.8% done
    total 8 docs, 149 bytes
    total 0.010 sec, 14900.00 bytes/sec, 800.00 docs/sec
    
    注:-all 参数将重构 sphinx.conf 中列出的所有索引。如果不需要重构所有索引,您可以使用其他参数只对部分索引进行重构。
  3. 您现在可以使用如下所示的代码用 search 实用程序测试索引(不必运行 searchd 即可使用 search)。
    清单 11. 用 search 测试索引
    $ /usr/local/bin/search --config /usr/local/etc/sphinx.conf ENG
    Sphinx 0.9.7
    Copyright (c) 2001-2007, Andrew Aksyonoff
    
    index 'catalog': query 'ENG ': returned 2 matches of 2 total in 0.000 sec
    
    displaying matches:
    1. document=8, weight=1, assembly=5, model=7
            id=8
            partno=ENG088
            description=Cylinder head
            price=55
    2. document=9, weight=1, assembly=5, model=3
            id=9
            partno=ENG976
            description=Large cylinder head
            price=65
    
    words:
    1. 'eng': 2 documents, 2 hits
    
    $ /usr/local/bin/search --config /usr/local/etc/sphinx.conf wind 
    Sphinx 0.9.7
    Copyright (c) 2001-2007, Andrew Aksyonoff
    
    index 'catalog': query 'wind ': returned 2 matches of 2 total in 0.000 sec
    
    displaying matches:
    1. document=1, weight=1, assembly=3, model=1
            id=1
            partno=WIN408
            description=Portal window
            price=423
    2. document=5, weight=1, assembly=3, model=1
            id=5
            partno=WIN958
            description=Windshield, front
            price=500
    
    words:
    1. 'wind': 2 documents, 2 hits
    
    $ /usr/local/bin/search \
    --config /usr/local/etc/sphinx.conf --filter  model 3 ENG
    Sphinx 0.9.7
    Copyright (c) 2001-2007, Andrew Aksyonoff
    
    index 'catalog': query 'ENG ': returned 1 matches of 1 total in 0.000 sec
    
    displaying matches:
    1. document=9, weight=1, assembly=5, model=3
            id=9
            partno=ENG976
            description=Large cylinder head
            price=65
    
    words:
    1. 'eng': 2 documents, 2 hits
    

第一条命令 /usr/local/bin/search --config /usr/local/etc/sphinx.conf ENG 在零件号中找到了两个含有 ENG 的结果。第二条命令/usr/local/bin/search --config /usr/local/etc/sphinx.conf wind 在两个零件描述中找到了子字符串 wind。而第三条命令把结果限定为 model 为 3 的条目。

回页首

编写代码

最后,您可以编写 PHP 代码来调用 Sphinx 搜索引擎。Sphinx PHP API 非常小并且易于掌握。清单 12 是一个小型 PHP 应用程序,用于调用 searchd 以得到使用上面所示的最后一条命令得到的相同结果(“在属于型号 3 的名称中找到含有 ‘cylinder’ 的所有零件”)。

清单 12. 从 PHP 调用 Sphinx 搜索引擎
 
 

要测试代码,需要为 Sphinx 创建 log 目录,启动 searchd,然后运行 PHP 应用程序,如下所示:

清单 13. PHP 应用程序
$ sudo mkdir -p /var/log/searchd
$ sudo /usr/local/bin/searchd --config /usr/local/etc/sphinx.conf
$ php search.php 
9
Array
(
    [fields] => Array
        (
            [0] => partno
            [1] => description
        )

    [attrs] => Array
        (
            [assembly] => 1
            [model] => 1
        )

    [matches] => Array
        (
            [9] => Array
                (
                    [weight] => 1
                    [attrs] => Array
                        (
                            [assembly] => 5
                            [model] => 3
                        )

                )

        )

    [total] => 1
    [total_found] => 1
    [time] => 0.000
    [words] => Array
        (
            [cylind] => Array
                (
                    [docs] => 2
                    [hits] => 2
                )

        )
)

输出为 9:匹配的单行的正确主键。如果 Sphinx 找到匹配,相关数组 $result 将包含名为 results 的元素。浏览 print_r() 的输出以查看返回的其他内容。

注意事项:total_found 是在索引中找到的匹配总数,而 found 是返回的结果数。这两者可能不同,因为您可以更改每次返回多少个匹配结果以及要返回哪批匹配结果,哪个结果利于对冗长的结果列表分页。请查看 API 调用 SetLimits()。一个分页示例是用 $cl->SetLimits( ( $page - 1 ) * SPAN, SPAN ) 调用搜索引擎返回第一批、第二批、第三批(依此类推)SPAN 匹配结果,这取决于显示哪个页面。

回页首

结束语

Sphinx 还有更多的功能可以利用。我在这里仅仅介绍了最浅显的一部分,但是您现在有一个可以工作的现实示例作为基石来扩展您的技能。

仔细研读随发行版附带的样例 Sphinx 配置文件 /usr/local/etc/sphinx.conf.dist。该文件中的注释将说明每个 Sphinx 参数可以实现的功能;展示如何创建分布式冗余配置;并说明如何继承基本设置以避免源代码及索引中的重复。Sphinx README 文件还是十分丰富的信息源,包括如何将 Sphinx 直接嵌入 MySQL V5 —— 不需要使用守护程序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值