如何用sphinx进行多应用的图片搜索
====== 如何用sphinx进行多应用的图片搜索 ======
作者::Dony,<wangwq(at)cgfinal.com>,版权所有,转载请声明来源与作者,在[[http://code.cgfinal.com/?p=73|这里]]也可以浏览本文。
离上一次写《[[http://www.sphinxsearch.com/wiki/doku.php?id=sphinx_chinese_tutorial|sphinx速成指南]]》介绍的文章有几年时间了,随着对sphinx的了解的深入,越来越觉得有必要将一些经验与大家分享交流,上次写的时候比较勿忙,有些地方没写细,这次我将结合案例,希望可以给大家带来启发。
sphinx能实现的功能我就不细讲了,不清楚的同学可以看一下sphinx的官方手册,或我以前写的那篇《[[http://www.sphinxsearch.com/wiki/doku.php?id=sphinx_chinese_tutorial|sphinx速成指南]]》。这里主要以实例讲一下sphinx的应用(以sphinx 0.99[r2117]为例)。
===== 1 前言 =====
本文涉及Sphinx全文检索、MySQL、PHP等知识,对这些知识需要有点了解。虽然我写的是一个类似教程的文章,但本文中的涉及的技术已在[[http://www.cgfinal.com|CGFinal]]的[[http://find.cgfinal.com|CGFind搜索系统]]中应用,为了方便,我简化了本文的应用数据表结构。
我有两个应用,一个是画廊,一个是新闻文章,需要实现对画廊与新闻文章的图片搜索,要求通过提供一个输入关键字的搜索框就可以搜出画廊与新闻文章中的图片,最终效果类似如下:
{{cgfind_img.png|}}
首先,我要设计四个表,表结构如下:
^ 画廊表名: t_gallery ^ 新闻文章表名:t_article ^ 图片信息表:t_pic ^ 索引记数表:t_sphcounter ^
| 建表语句:\\ create table t_gallery(\\ `ID` int(11) NOT NULL auto_increment,\\ `TITLE` varchar(100) not NULL,\\ `PICURI` varchar(255) NULL,\\ `USERID` int(11) NULL,\\ `MEMODESC` text,\\ `ADDTIME` int(11) NULL,\\ HTMLURL varchar(255) null,\\ CATEGORYID int,\\ RANK tinyint null default 0,\\ PRIMARY KEY(`ID`),\\ INDEX(`USERID`)\\ ); | 建表语句:create table t_article(\\ `ID` int(11) NOT NULL auto_increment,\\ `SUBJECT` varchar(100) NOT NULL\\ ,`AUTHOR` varchar(200) default NULL,\\ `COMEFROM` varchar(200) default NULL,\\ `HTMLURL` varchar(200) default NULL,`CATEGORYID` int(6) default NULL,\\ `CONTENTS` mediumtext,\\ `ADDTIME` int not null,`STATE` tinyint(1) default '0',\\ `EDITORID` int,PRIMARY KEY (`ID`),\\ index(`CATEGORYID`));| 建表语句:\\ create table `t_pic`(\\ `ID` int not null auto_increment,\\ `IMAGEURL` varchar(255) not null,\\ `WIDTH` varchar(10),\\ `HEIGHT` varchar(10),\\ `MIMETYPE` varchar(30),\\ `FILESIZE` varchar(30),\\ `APPID` int null,\\ `INFOID` int null,\\ `INFOURL` varchar(255),\\ index(`APPID`,`INFOID`),\\ primary key(`ID`)); | 建表语句:\\ create table t_sphcounter (\\ counter_id int primary key not null,\\ max_doc_id int not null\\ ); |
| 说明:\\ ID 主键\\ TITLE 画廊作品名称\\ PICURI 作品图片的URI地址\\ USERID 作者用户ID\\ MEMODESC 作品描述\\ RANK 等级\\ HTMLURL 作品对应的URL地址\\ ADDTIME 添加时间 | 说明:\\ ID 主键\\ SUBJECT 文章标题\\ AUTHOR 文章作者\\ COMEFROM 文章来源/出自\\ HTMLURL 静态文章的URL地址\\ CATEGORYID 文章所属分类ID\\ CONTENTS 文章内容\\ ADDTIME 添加时间\\ STATE 文章状态(1:发布,0:未发布)\\ EDITORID 编辑用户ID | 说明:\\ IMAGEURL 图片地址\\ WIDTH 宽\\ HEIGHT 高\\ MIMETYPE 文件的MEME类型,如image/jpeg,image/png等\\ FILESIZE 文件大小\\ APPID 应用ID,1:画廊,2:新闻文章\\ INFOID 应用信息ID\\ INFOURL 应用信息URL | 说明:\\ counter_id 标识数据表的ID(我们将1表示t_gallery表,2表示t_article表)\\ max_doc_id 数据表目前最新一条被主索引索引的主键ID |
t_gallery与t_article是我的画廊应用与新闻文章应用,t_pic则是图片信息表,它将画廊作品图片与新闻文章图片的信息都归纳到这里,以便sphinx索引搜索。
===== 2 开发目标 =====
根据用户搜索的关键字找出画廊表与文章表中的相关图片,要求图片可以分壁纸、大、小三种规格,要能显示图片的宽高,搜索结果统一,不将画廊表与文章表分为两个搜索结果,同时要保证只会搜出画廊表中RANK>=3的作品与文章表中STATE=1的文章。
===== 3.实现思路分析 =====
?(1)通过搜索画廊作品名称与含有图片的文章标题,基本上就可以达到我的图片搜索要求。\\
?(2)从上面两张表的结构我们可以发现画廊表是一条记录一张图片,而且图片没有记录宽与高;而文章表没有具体记录文章中含有的图片信息,因此我们可能需要有一张表来记录图片的具体信息,如图片地址,图片宽度,图片高度,图片文件大小,图片格式等。这张表叫t_pic。表结构与说明在前言已说明\\
?(3)通过sphinx搜索出符合要求的t_pic表的id记录集,再将t_pic表的这个id记录集对应的INFOID与文章表及画廊表并联查询,搜索结果即可展现出我想要的内容与效果。
===== 4 开发难点 =====
?(1)提取画廊表与文章内容中的图片信息,插入至t_pic表;\\
?(2)编写sphinx的全文检索索引数据源的SQL,将数据索引起来;\\
?(3)将t_pic表与画廊表、文章表两个数据表并联查询取出符合条件的内容。
===== 5 实现步聚 =====
==== 5.1 向t_pic表添加图片信息数据 ====
创建t_pic表,修改画廊与文章的保存程序,让画廊作品与文章内容在保存时,自动将画廊作品以及文章内容中的图片信息提取出来插入到t_pic表中。文章内容中的图片地址可以通过模式匹配取出来。再利用getimagesize或imagemagick对这些图片URL地址分析,提取图片的宽高等信息。对于画廊表与文章表已有的信息,可以写一个分析程序,将图片信息提取出来存入t_pic表。具体如何写分析程序这里就略过,下图给出t_pic表的数据样例,具体各列字段的含义请参照[[#1 前言|前言]]的说明。
{{t_pic.gif|}}
==== 5.2 编写sphinx.conf文件 ====
由于我们的应用数据是经常更新的,为了保证搜索能搜索最新添加的内容,sphinx的索引数据必须经常更新。随着我们应用数据量的增长,sphinx每次重建索引的时间将会越变越长,为不影响前台搜索的使用,按照sphinx官方手册指导说明,我们可以借助一个中间表t_sphcounter将索引分为主索引与次索引。主索引数据量大,重建慢,更新频率低,次索引数据量小,重建快,更新频率高。第一次建立sphinx主索引后,t_sphcounter会记录最近一条被索引的信息的ID(这里我们将它暂叫MAXID),当应用数据有更新时,ID>MAXID以上的数据都未被主索引索引,此时可以让次索引索引这一部分数据。在我们搜索时,对主索引与次索引同时搜索就基本可以搜索最新的、全部的数据了。根据我们应用数据的更新频率,可以设为每10分钟或每小时重建一次次索引,而主索引由于相当于是整个应用的全部数据的索引,在重建时会耗时较长,可以设为每天更新一次或相对次索引更长一段时间更新一次。\\
由于画廊表与文章表表结构不一样,为了方便使用sphinx,我们在建立画廊与文章表的图片搜索索引时,尽可能让索引数据源结构一致。
=== 5.2.1 数据源配置 ===
**(1)新闻文章图片的主索引数据源:**\\
<html>
source img_article:tappy{
sql_query_pre = set names utf8
sql_query_pre = REPLACE INTO t_sphcounter SELECT 2, MAX(ID) FROM t_article
sql_query_range = SELECT MIN(ID),MAX(ID) FROM t_article
sql_range_step = 1000
sql_query = SELECT a.ID, concat(INFOID,'.',APPID) as APPINFOID,APPID,INFOID,WIDTH,
HEIGHT,(HEIGHT/WIDTH) AS HWSCALE,FILESIZE,SUBJECT,STATE,ADDTIME,3 as "RANK",CATEGORYID