首页 > 代码库 > [连载]Java程序设计(03)---任务驱动方式:寻找高富帅和屌丝

[连载]Java程序设计(03)---任务驱动方式:寻找高富帅和屌丝

1. Sphin x简介 

1.1. 什么是全文检索 

全文检索是指以文档的全部文本信息作为检索对象的一种信息检索技术 。检索的对象有可能是文章的标题,也有可能是文章的作者,也有可能是文章摘要或内容。 

1.2. 介绍 

Sphin x是一个基于SQL的全文检索引擎,可以结合MySQL,PostgreSQL做全文搜索,它可以提供比数据库本身更专业的搜索功能 ,使得应用程序更容易实现专业化的全文检索。Sphin x特别为一些脚本语言设计搜索API接口 ,如PHP ,Python,Perl,Ruby等,同时为MySQL也设计了一个存储引擎插件。 

1.3. Sphin x的特性 

高速索引 (在新款CPU上,近10 MB/秒);
高速搜索 (2-4G的文本量中平均查询速度不到0.1秒);
高可用性 (单CPU上最大可支持100 GB的文本,100M文档);
提供良好的相关性排名
支持分布式搜索;
提供文档摘要生成;
提供从MySQL内部的插件式存储引擎上搜索
supports boolean, phrase, and word proximity queries;
支持每个文档多个全文检索域(默认最大32个);
支持每个文档多属性;
支持断词;
支持单字节编码与UTF-8编码;
supports English stemming, Russian stemming, and Soundex for morphology;
支持MySQ(MyISAM和InnoDB 表都支持);
支持PostgreSQL.2. Sphin x安装(For MySQL) 2.1. Windows下安装 从http://dev.mysql .com/ 下载MySQL5.0.45版安装配置好MySQL,采用utf-8字符 

 

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

要为站点提供自定义搜索功能,您必须有数据源和搜索该数据源的功能。对于 Web 应用程序,数据源通常是一个关系数据库,其中内置了一些搜索功能(Equality 是一个简单的搜索运算符,与 SQL 运算符LIKE 一样)。但是,一些搜索可能比数据库可以执行的搜索更加具体,或者搜索可能过于复杂,而导致固有的 SQL JOIN 反应迟钝。

要加速搜索,您可以重新安排表,并由此简化底层查询(表和 SQL 查询优化高度依赖于模式和引擎。可通过在线搜索查找有关数据库性能的各种文章和书籍)。此外,您可以添加一个专门化的搜索引擎。应用哪种形式的搜索引擎还依赖于数据的形式(和数量)和预算。有许多选择可用:您可以将一个 Google 工具连接到您的络中,购买 Endeca 或其他大型商业搜索产品,或者尝试 Lucene。但是在很多情况下,使用商业产品都有点小题大做,或者浪费运营预算,并且 Lucene 在 2007 年 7 月编写时并未提供 PHP API。

作为一个备选方案,考虑一下 Sphinx,它是一种开源和免费的搜索引擎,可以非常快速地搜索文本。例如,在一个几乎有 300,000 行及五个索引列(每列包含大约 15 个单词)的活动数据库中,Sphinx 可以在 1/100 秒内得到 “这些单词中任何一个单词” 的搜索结果(在运行 Debian Linux? Sarge 的 2-GHz AMD Opteron 处理器、1 GB RAM 的计算机上)。

Sphinx 提供了大量功能,包括:

  • 它可以为能够表示为字符串的所有数据建立索引。
  • 它可以以各种方式为相同数据建立索引。对于多个索引,每个索引都针对特定目的而定制,您可以选择最适当的索引来优化搜索结果。
  • 它可以把属性与每条索引数据关联起来。然后您可以使用一个或多个属性来进一步过滤搜索结果。
  • 它支持词法,因此搜索单词 “cats” 还会找到词根 “cat”。
  • 您可以在许多计算机中分发 Sphinx 索引,从而提供故障恢复功能。
  • 它可以创建任意长度的单词前缀索引和可变长度的中缀子字符串的索引。例如,一个零件号可以是 10 个字符宽。前缀索引将匹配位于字符串开头处的所有可能的子字符串。中缀索引将匹配在字符串内任意位置的子字符串。
  • 您可以在 MySQL V5 内将其作为存储引擎运行,降低使用其他守护程序的需求(通常被视为另一个故障点)。

您可以在 Sphinx 源代码附带的 README 文件中或通过在线资料找到完整的功能列表。Sphinx Web 站点还列出了已经部署了 Sphinx 的若干个项目。

Sphinx 是用 C++ 编写、用 GNU 编译器构建、支持 64 位支持平台,并在 Linux、UNIX?、Microsoft? Windows? 和 Mac OS X 上运行。构建 Sphinx 十分简单:下载并解压缩代码,然后运行./configure && make && make install 命令。

默认情况下,Sphinx 实用程序将被安装到 /usr/local/bin/ 中,并且所有 Sphinx 组件的配置文件都位于 /usr/local/etc/sphinx.conf 中。

Sphinx 有三个组件:索引生成器、搜索引擎和命令行 search 实用程序:

  • 索引生成器被称为索引器。它将查询数据库,为结果的每行中的每列建立索引,并且将每个索引条目绑定到行的主键上。
  • 搜索引擎是名为 searchd 的守护程序。该守护程序将接收搜索词和其他参数,快速遍历一个或多个索引,并返回结果。如果找到匹配,searchd 将返回一个主键数组。对于这些键,应用程序可以针对相关数据库运行查询来查找包含匹配的完整记录。Searchd 将在端口 3312 上通过套接字连接与应用程序进行通信。
  • 便捷的 search 实用程序使您可以从命令行构造搜索而无需编写代码。如果 searchd 返回匹配,则 search 将查询数据库并显示匹配集中的行。search 实用程序对于调试 Sphinx 配置和执行临时搜索十分有用。

 

集成 Sphinx 软件

要应用 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 表中的零件条目。partnodescription 列是要搜索的主要文本,而assemblymodel 列用作进一步过滤结果的组。视图就绪后,构造数据源查询就是小事一桩。清单 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
}