博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【转载】Discuz!NT企业版之Sphinx全文搜索
阅读量:7118 次
发布时间:2019-06-28

本文共 28697 字,大约阅读时间需要 95 分钟。

 

      作为Discuz!NT企业版中的一员,在设计企业级搜索架构之初,就考虑了海量数量,准实时索引更新,并发访问,安装布署等诸多方面。目前在生产环境下被广泛使用的开源搜索引擎中,sphinx以其强大快速的索引功能,优异的并发响应性能,方面灵活的布署,分布式查询等诸多因素而倍受青睐。
      目前Sphinx广泛应用在Linux平台上,尽管官方所发布的产品中也有window版本,并且支持mssql数据库,但在使用过程中才发现,其只在发布的windows平台下的版本里才支持mssql数据库,而linux平台下只有MySql,PostgreSQL这两种数据库支持。尽管后来在网上查找资料时发现可以使用UNIXODBC方式在LINUX下链接MsSql数据库,但在unixodbc的官方网站下载的源码包中却发现其并不包含makefile文件,从而导致下载解压的源码包无法编译(看来unixodbc开发者也疏忽了),当然即使ODBC能链接成功,但效率上还是可能存在问题。
      而在window下尽管能实现链接mssql和创建索引以及查询,但在进行压力测试时发现即使50并发也会让sphinx守护进程疲于奔命到停止响应(后来在Linux下布署,发现同样数据索引量同一台机器,可以支持至少200-300并发),而sphinx的宿主环境是一台单核1.5G+1.5g内存的普通台式机(现在主流笔记本的配置都比它高得多)。所以就并发性而言,目前主流平台还是建立在linux上.
 
      正因为如此,我才在解决方案中引入了一个mysql数据库,来实现下面三个目标:
      1.为LINUX平台下SPHINX提供可访问的数据源。   
      2.充当快照功能(Slave database)解决当主数据库(Master database)宕机后,不会影响SPHINX创建索引了,这样看就相当于备份功能。  
      3.解决当创建SPHINX索引时,对主数据库的访问压力。
      下面这张图简单说明了Sphinx(Linux) + MySql + Discuz!NT的关系:
       
    
      如上面所说的,我们在产品中引入了Sphinx客户端API,而服务端则通过LINUX+SPHINX守护进程来实现,所以这篇文章要被分为两个部分,今天要说明的只是Discuz!NT方面的改动。下一篇将会介绍如何在LINUX下配置SPHINX及增量索引等相关工作。好了开始正文吧。
      首先为了简化安装,我写了一个文件类用于配置SPHINX客户端信息,如下(Discuz.Config\EntLibConfigInfo.cs):
     
///
 
<summary>
    
///
 Sphinx企业级查询配置信息
    
///
 
</summary>
    
public
 
class
 SphinxConfig
    {
        
///
 
<summary>
        
///
 Mysql增量数据库链接地址
        
///
 
</summary>
        
public
 
string
 MySqlConn;
        
///
 
<summary>
        
///
 是否启用Sphinx搜索
        
///
 
</summary>
        
public
 
bool
 Enable;
        
///
 
<summary>
        
///
 Sphinx服务地址
        
///
 
</summary>
        
public
 
string
 SphinxServiceHost;
        
///
 
<summary>
        
///
 Sphinx服务端口
        
///
 
</summary>
        
public
 
int
 SphinxServicePort 
=
 
3312
;
      
        ......
    }

 

      该配置类中提供了是否开启SPHINX查询(Enable),以及MYSQL数据库链接,以及SPHINX服务端的地址端口信息等。

      下面介绍一下Sphinx的客户端代码(C#)实现,该代码被放到了Discuz.EntLib这个项目中(位于SphinxClient\),而该项目是一个基于GNU的开源项目,其类"SphinxClient"实现了构造方法和相应访问SPHINX服务端守护进程的方法,如下:
              

        这些方法的名称和参数信息与SPHINX开放的API是对应的,而相应的SPHINX文档可以从官方下载,这里只提供一个中文文档的下载地址,也就是CORESEEK的文档链接, 如下:

       

       这份手册中介绍了大部分API方法的使用和示例,是目前为止网上找到最全的中文文档了。
       有了客户端,我们还要在已有的搜索代码中植入SPHINX查询逻辑代码。
       在原来的产品中,搜索功能是使用SQLSERVER全文检索的方法提供的,其原理是:
    
       使用SQLSERVER全文检索方法查询帖子分表(dnt_posts,表结构如下图所示)的MESSAGE字段:

    

 

       而该字段是Text类型,所以在一次性查询出所有记录的pid字段后,以distinct方法过滤其中记录重复的tid信息,最终会返回tid字段并将其放入到数据库中,相应SQL语句构造方法参照如下(Discuz.Data.SqlServer/GlobalManage.cs):

 

ExpandedBlockStart.gif
private
 
string
 GetSearchPostContentSQL(
int
 posterId, 
string
 searchForumId, 
int
 resultOrder, 
int
 resultOrderType, 
int
 searchTime, 
int
 searchTimeType, 
int
 postTableId, StringBuilder strKeyWord)
{           
    StringBuilder sqlBuilder 
=
 
new
 StringBuilder();
    
string
 orderfield 
=
 
"
lastpost
"
;
    
switch
 (resultOrder)
    {
        
case
 
1
:
            orderfield 
=
 
"
tid
"
;
            
break
;
        
case
 
2
:
            orderfield 
=
 
"
replies
"
;
            
break
;
        
case
 
3
:
            orderfield 
=
 
"
views
"
;
            
break
;
        
default
:
            orderfield 
=
 
"
lastpost
"
;
            
break
;
    }
    sqlBuilder.AppendFormat(
"
SELECT DISTINCT [{0}posts{1}].[tid],[{0}topics].[{2}] FROM [{0}posts{1}] LEFT JOIN [{0}topics] ON [{0}topics].[tid]=[{0}posts{1}].[tid] WHERE [{0}topics].[displayorder]>=0 
"
,
                             BaseConfigs.GetTablePrefix,
                             postTableId,
                             orderfield);
    
if
 (searchForumId 
!=
 
""
)
        sqlBuilder.AppendFormat(
"
 AND [{0}posts{1}].[fid] IN ({2})
"
, BaseConfigs.GetTablePrefix, postTableId, searchForumId);
    
if
 (posterId 
!=
 
-
1
)
        sqlBuilder.AppendFormat(
"
 AND [{0}posts{1}].[posterid]={2}
"
, BaseConfigs.GetTablePrefix, postTableId, posterId);
    
if
 (searchTime 
!=
 
0
)
        sqlBuilder.AppendFormat(
"
 AND [{0}posts{1}].[postdatetime] {2} '{3}'
"
,
                                  BaseConfigs.GetTablePrefix,
                                  postTableId,
                                  searchTimeType 
==
 
1
 
?
 
"
<
"
 : 
"
>
"
,
                                  DateTime.Now.AddDays(searchTime).ToString(
"
yyyy-MM-dd 00:00:00
"
));
    
string
[] keywordlist 
=
 Utils.SplitString(strKeyWord.ToString(), 
"
 
"
);
    strKeyWord 
=
 
new
 StringBuilder();
    
for
 (
int
 i 
=
 
0
; i 
<
 keywordlist.Length; i
++
)
    {
        
if
 (strKeyWord.Length 
>
 
0
)
            strKeyWord.Append(
"
 OR 
"
);
        
if
 (GeneralConfigs.GetConfig().Fulltextsearch 
==
 
1
)
        {
            strKeyWord.AppendFormat(
"
CONTAINS(message, '\
"
*
"
, BaseConfigs.GetTablePrefix, postTableId);
            strKeyWord.Append(keywordlist[i]);
            strKeyWord.Append(
"
*\
"'
) ");
        }
        
else
            strKeyWord.AppendFormat(
"
[{0}posts{1}].[message] LIKE '%{2}%' 
"
,
                                     BaseConfigs.GetTablePrefix,
                                     postTableId,
                                     RegEsc(keywordlist[i]));
    }
    
if
 (keywordlist.Length 
>
 
0
)
        sqlBuilder.Append(
"
 AND 
"
 
+
 strKeyWord.ToString());
    sqlBuilder.AppendFormat(
"
ORDER BY [{0}topics].
"
, BaseConfigs.GetTablePrefix);
    
switch
 (resultOrder)
    {
        
case
 
1
:
            sqlBuilder.Append(
"
[tid]
"
);
            
break
;
        
case
 
2
:
            sqlBuilder.Append(
"
[replies]
"
);
            
break
;
        
case
 
3
:
            sqlBuilder.Append(
"
[views]
"
);
            
break
;
        
default
:
            sqlBuilder.Append(
"
[lastpost]
"
);
            
break
;
    }
    
return
 sqlBuilder.Append(resultOrderType 
==
 
1
 
?
 
"
 ASC
"
 : 
"
 DESC
"
).ToString();
}

 

 

         如果上述的构造方法所拼接出的SQL语句被顺利执行后,就会在相应的dnt_searchcaches表中生成一条记录,形如:   

    

<
ForumTopics
>
1,5,6,10,11,12,13,2,26,25,36,41,42,44,52,53,56,61,70,76,57,105,114,115,131,137
</
ForumTopics
>

 

       注:<ForumTopics>表示其是论坛搜索的结果(因为产品中同时也提供了空间相册搜索功能,所以这样加以标识).

       而dnt_searchcacheds数据字典如下(上面的ForumTopics对应表中的tids字段:text类型 ):

           

 

        

      然后根据这些tid记录,按分页的大小一次获取其中一段数据(比如头10条:1,5,6,10,11,12,13,2,26,25),然后再用这段tid集合作为where条件 放到类似下面的查询语句中运行,就会获取相应的主题列表了(查询结果以主题列表而不是帖子列表方式呈现,这也是为什么要在GetSearchPostContentSQL中进行distinct的原因,因为一个主题可以有多个帖子,即1:n):
       select * from dnt_topics where tid in (tid集合)
      原理清楚之后,下面就是加入SPHINX查询逻辑了。因为SPHINX对全文索引进行查询时,会返回相应的documemntId,相应对帖子分表中的pid字段,所以只要将逻辑代码放到GetSearchPostContentSQL中就可以了,这里使用了配置文件开关的方式来标识是否执行SPHINX查询,如下:
ExpandedBlockStart.gif

private
 
string
 GetSearchPostContentSQL(
int
 posterId, 
string
 searchForumId, 
int
 resultOrder, 
int
 resultOrderType, 
int
 searchTime, 
int
 searchTimeType, 
int
 postTableId, StringBuilder strKeyWord)
{           
    
//
如果开启sphinx全文搜索时
    
if
 (
!
string
.IsNullOrEmpty(strKeyWord.ToString()) 
&&
 EntLibConfigs.GetConfig() 
!=
 
null
 
&&
 EntLibConfigs.GetConfig().Sphinxconfig.Enable)
    {
        
return
 GetSphinxSqlService().GetSearchPostContentSQL(posterId, searchForumId, resultOrder, resultOrderType, searchTime, searchTimeType, postTableId, strKeyWord);
    }
    StringBuilder sqlBuilder 
=
 
new
 StringBuilder();
    
string
 orderfield 
=
 
"
lastpost
"
;
    
switch
 (resultOrder)
    {
        
case
 
1
:
            orderfield 
=
 
"
tid
"
;
            
break
;
      
    ......

 

        

         通过上述代码,可以看出GetSphinxSqlService()这个方法就是提供SPHINX查询和数据服务的接口,该接口定义如下:

ExpandedBlockStart.gif
///
 
<summary>
///
 查询服务数据操作接口
///
 
</summary>
public
 
interface
 ISqlService
{
    
///
 
<summary>
    
///
 创建Sphinx的数据表(目前只支持mysql数据库类型)
    
///
 
</summary>
    
///
 
<param name="tableName">
当前分表名称
</param>
    
///
 
<returns></returns>
    
bool
 CreatePostTable(
string
 tableName);
    
///
 
<summary>
    
///
 创建Sphinx数据表帖子
    
///
 
</summary>
    
///
 
<param name="tableName">
当前分表名称
</param>
    
///
 
<param name="pid">
帖子ID
</param>
    
///
 
<param name="tid">
主题ID
</param>
     
    
///
 
<param name="fid">
所属版块ID
</param>
    
///
 
<param name="posterid">
发帖人
</param>
    
///
 
<param name="postdatetime">
发帖日期
</param>
    
///
 
<param name="title">
标题
</param>
    
///
 
<param name="message">
内容
</param>
    
///
 
<returns></returns>
    
int
 CreatePost(
string
 tableName, 
int
 pid, 
int
 tid, 
int
 fid, 
int
 posterid, 
string
 postdatetime, 
string
 title, 
string
 message);
    
///
 
<summary>
    
///
 更新Sphinx数据表帖子
    
///
 
</summary>
    
///
 
<param name="tableName">
当前分表名称
</param>
    
///
 
<param name="pid">
帖子ID
</param>
    
///
 
<param name="tid">
主题ID
</param>
     
    
///
 
<param name="fid">
所属版块ID
</param>
    
///
 
<param name="posterid">
发帖人
</param>
    
///
 
<param name="postdatetime">
发帖日期
</param>
    
///
 
<param name="title">
标题
</param>
    
///
 
<param name="message">
内容
</param>
    
///
 
<returns></returns>
    
int
 UpdatePost(
string
 tableName, 
int
 pid, 
int
 tid, 
int
 fid, 
int
 posterid, 
string
 postdatetime, 
string
 title, 
string
 message);
    
///
 
<summary>
    
///
 获取要搜索的主题ID(Tid)信息
    
///
 
</summary>
    
///
 
<param name="posterId">
发帖者id
</param>
    
///
 
<param name="searchForumId">
搜索版块id
</param>
    
///
 
<param name="resultOrder">
结果排序方式
</param>
    
///
 
<param name="resultOrderType">
结果类型类型
</param>
    
///
 
<param name="searchTime">
搜索时间
</param>
    
///
 
<param name="searchTimeType">
搜索时间类型
</param>
    
///
 
<param name="postTableId">
当前分表ID
</param>
    
///
 
<param name="strKeyWord">
关键字
</param>
    
///
 
<returns></returns>
    
string
 GetSearchPostContentSQL(
int
 posterId, 
string
 searchForumId, 
int
 resultOrder, 
int
 resultOrderType, 
int
 searchTime, 
int
 searchTimeType, 
int
 postTableId, System.Text.StringBuilder strKeyWord);
}

 

       设计这个接口的目的首先是解除Discuz.EntLib.dll与其它DLL文件的互相依赖。第二就是为了当本机用户发表或更新帖子信息时,会调用这个接口的中的相应方法来创建(CreatePost)或更新(UpdatePost)mysql数据库中的相应帖子记录,以确保sphinx获取索引数据的有效性。

       可以通过反射的方法实例化该接口对象以便访问其中的方法,如下(GlobalManage.cs):

ExpandedBlockStart.gif
#region
 sphinx SQL服务
 
private
 
static
 SphinxConfig.ISqlService sphinxSqlService;
 
private
 
static
 SphinxConfig.ISqlService GetSphinxSqlService()
 {
     
if
 (sphinxSqlService 
==
 
null
)
     {
         
try
         {
             sphinxSqlService 
=
 (SphinxConfig.ISqlService)Activator.CreateInstance(Type.GetType(
"
Discuz.EntLib.SphinxClient.SphinxSqlService, Discuz.EntLib
"
false
true
));
         }
         
catch
         {
             
throw
 
new
 Exception(
"
请检查BIN目录下有无Discuz.EntLib.dll文件
"
);
         }
     }
     
return
 sphinxSqlService;
 }
 
#endregion

 

     

       而在Discuz.EntLib中提供了该接口的MYSQL类型数据库实现方法(Discuz.EntLib\SphinxClient\SphinxSqlService.cs),如下:

ExpandedBlockStart.gif
public
 
class
 SphinxSqlService : Discuz.Config.SphinxConfig.ISqlService
{
        
private
 SphinxConfig sphinxConfig 
=
 EntLibConfigs.GetConfig().Sphinxconfig;
    
        
public
 
int
 CreatePost(
string
 tableName, 
int
 pid, 
int
 tid, 
int
 fid, 
int
 posterid, 
string
 postdatetime, 
string
 title, 
string
 message)
        {
            DbParameter[] prams 
=
 {                                    
                                       MakeParam(
"
?pid
"
, (DbType)MySqlDbType.Int32, 
4
, ParameterDirection.Input, pid),
                                       MakeParam(
"
?tid
"
, (DbType)MySqlDbType.Int32, 
4
, ParameterDirection.Input, tid),
                                       MakeParam(
"
?fid
"
, (DbType)MySqlDbType.Int16, 
2
, ParameterDirection.Input, fid),
                                       MakeParam(
"
?posterid
"
, (DbType)MySqlDbType.Int32, 
4
, ParameterDirection.Input, posterid),
                                       MakeParam(
"
?postdatetime
"
, (DbType)MySqlDbType.VarString, 
20
, ParameterDirection.Input, postdatetime),
                                       MakeParam(
"
?title
"
, (DbType)MySqlDbType.VarString, 
60
, ParameterDirection.Input, title),
                                       MakeParam(
"
?message
"
, (DbType)MySqlDbType.Text, 
0
, ParameterDirection.Input, message)
                                   };
            
string
 commandText 
=
 
"
SET NAMES utf8;INSERT INTO  `
"
 
+
 tableName 
+
 
"
` (`pid`,`tid`,`fid`,`posterid`,`postdatetime`,`title`,`message`) VALUES(?pid,?tid,?fid,?posterid,?postdatetime,?title,?message)
"
;
            
try
            {               
                
return
 TypeConverter.ObjectToInt(ExecuteScalar(commandText, prams));
            }
            
catch
 
            {
                CreatePostTable(tableName);
                
return
 TypeConverter.ObjectToInt(ExecuteScalar(commandText, prams));
            }
        }
       
        
public
 
bool
 CreatePostTable(
string
 tableName)
        {
            EntLibConfigInfo entLibConfigInfo 
=
 EntLibConfigs.GetConfig();
            
//
数据库MY.ini文件中也要指定或在安装实例是即指定为utf-8
            
//
SET NAMES utf8;CREATE DATABASE IF NOT EXISTS test;
            
string
 commandText 
=
 
string
.Format(
"
SET NAMES utf8;
"
 
+
                                    
"
CREATE TABLE IF NOT EXISTS `{0}` (
"
 
+
                                    
"
`pid` INT(11) NOT NULL ,
"
 
+
                                    
"
`tid` INT(11) NOT NULL ,
"
 
+
                                    
"
`fid` INT(11) NOT NULL ,
"
 
+
                                    
"
`posterid` INT(11) NOT NULL ,
"
 
+
                                    
"
`postdatetime` DATETIME NOT NULL,
"
 
+
                                    
"
`title` varchar(60) NOT NULL,
"
 
+
                                    
"
`message` TEXT NOT NULL,
"
 
+
                                    
"
PRIMARY KEY  (`pid`)
"
 
+
                                    
"
) DEFAULT CHARSET=utf8;
"
,
                                    tableName);
            ExecuteScalar(commandText, 
null
);
            
return
 
true
;
        }
        
public
 
int
 UpdatePost(
string
 tableName, 
int
 pid, 
int
 tid, 
int
 fid, 
int
 posterid, 
string
 postdatetime, 
string
 title, 
string
 message)
        {
            DbParameter[] prams 
=
 {                                    
                                       MakeParam(
"
?pid
"
, (DbType)MySqlDbType.Int32, 
4
, ParameterDirection.Input, pid),
                                       MakeParam(
"
?tid
"
, (DbType)MySqlDbType.Int32, 
4
, ParameterDirection.Input, tid),
                                       MakeParam(
"
?fid
"
, (DbType)MySqlDbType.Int16, 
2
, ParameterDirection.Input, fid),
                                       MakeParam(
"
?posterid
"
, (DbType)MySqlDbType.Int32, 
4
, ParameterDirection.Input, posterid),
                                       MakeParam(
"
?postdatetime
"
, (DbType)MySqlDbType.VarString, 
20
, ParameterDirection.Input, postdatetime),
                                       MakeParam(
"
?title
"
, (DbType)MySqlDbType.VarString, 
60
, ParameterDirection.Input, title),
                                       MakeParam(
"
?message
"
, (DbType)MySqlDbType.Text, 
0
, ParameterDirection.Input, message)
                                   };
            
string
 commandText 
=
 
"
SET NAMES utf8;UPDATE `
"
 
+
 tableName 
+
 
"
` SET  `tid` = ?tid, `fid` = ?fid, `posterid`= ?posterid,`postdatetime` = ?postdatetime,`title` = ?title, `message` = ?message WHERE `pid` = ?pid
"
;
            
try
            {
                
return
 ExecuteNonQuery(commandText, prams);
            }
            
catch
            {
                
return
 
0
;
            }
        }
        
public
 
string
 GetSearchPostContentSQL(
int
 posterId, 
string
 searchForumId, 
int
 resultOrder, 
int
 resultOrderType, 
int
 searchTime, 
int
 searchTimeType, 
int
 postTableId, StringBuilder strKeyWord)
        {
            
if
 (
string
.IsNullOrEmpty(strKeyWord.ToString()))
                
return
 
""
;
            SphinxClient cli 
=
 
new
 SphinxClient(sphinxConfig.SphinxServiceHost, sphinxConfig.SphinxServicePort);
            cli.SetLimits(
0
300000
);
//
30万条数据(单个帖子分表一般不应超过30万条记录)
            
if
 (searchForumId 
!=
 
""
)
                cli.SetFilter(
"
fid
"
, TypeConverter.StrToInt(searchForumId), 
false
);
            
if
 (posterId 
!=
 
-
1
)
                cli.SetFilter(
"
posterid
"
, posterId, 
false
);               
 
            
if
 (searchTime 
!=
 
0
)
            {
                
if
 (searchTimeType 
==
 
1
//
"<" 多少天之前 即: searchTimeType == 1 
                    cli.SetFilterRange(
"
postdatetime
"
, DateTimeHelper.ConvertToUnixTimestamp(DateTime.Now.AddYears(
-
10
)), DateTimeHelper.ConvertToUnixTimestamp(DateTime.Now.AddDays(searchTime)), 
false
);
                
else
  
//
">" 多少天之内 
                    cli.SetFilterRange(
"
postdatetime
"
, DateTimeHelper.ConvertToUnixTimestamp(DateTime.Now.AddDays(searchTime)), DateTimeHelper.ConvertToUnixTimestamp(DateTime.Now), 
false
);          
            }
            
if
(resultOrderType 
==
 
1
//
" ASC"
               cli.SetGroupBy(
"
tid
"
, (
int
)ResultsGroupFunction.Attribute, 
"
tid ASC
"
);
            
else
 
//
 DESC           
               cli.SetGroupBy(
"
tid
"
, (
int
)ResultsGroupFunction.Attribute);
          
            cli.SetGroupDistinct(
"
tid
"
);
            
            
string
 orderBy 
=
 
""
;
            
switch
 (resultOrder)
            {
                
case
 
1
:
//
tid
                    orderBy 
=
 
"
tid
"
;
                    
break
;
                
case
 
2
:
//
replies
                    orderBy 
=
 
"
tid
"
;
                    
break
;
                
case
 
3
:
//
views
                    orderBy 
=
 
"
tid
"
;
                    
break
;
                
default
:
                    orderBy 
=
 
"
postdatetime
"
;
                    
break
;
            }
            cli.SetSortMode((
int
)ResultsSortMode.Extended, orderBy 
+
 (resultOrderType 
==
 
1
 
?
 
"
 ASC
"
 : 
"
 DESC
"
));
            
            
foreach
 (
string
 keyword 
in
 Utils.SplitString(strKeyWord.ToString(), 
"
 
"
))
            {
                cli.AddQuery(keyword, BaseConfigs.GetTablePrefix 
+
 
"
posts
"
 
+
 postTableId);
//
搜索主索引
                cli.AddQuery(keyword, BaseConfigs.GetTablePrefix 
+
 
"
posts
"
 
+
 postTableId 
+
 
"
_stem
"
);
//
搜索增量索引
            }
          
            cli.SetWeights(
new
 
int
[] {
1
,
100
});
      
            SphinxResult[] results 
=
 cli.RunQueries();
            
string
 postid 
=
 
""
;
            
foreach
 (SphinxResult sr 
in
 results)
            {
                
foreach
(SphinxMatch sphinxMatch 
in
 sr.matches)
                {
                    
if
 (postid.Length 
<
 
280000
)
//
防止SQL语句过长而无法被执行,这里指定最长为28万
                    {
                        postid 
+=
 sphinxMatch.docId 
+
 
"
,
"
;
                    }
                }
            }        
            
if
 (
string
.IsNullOrEmpty(postid)) 
//
当没有搜索到任何数据时
                
return
 
""
;
   
            StringBuilder sqlBuilder 
=
 
new
 StringBuilder();
            sqlBuilder.AppendFormat(
"
SELECT [{0}posts{1}].[tid] FROM [{0}posts{1}] LEFT JOIN [{0}topics] ON [{0}topics].[tid]=[{0}posts{1}].[tid] WHERE [{0}posts{1}].[pid] IN ({2}) AND [{0}topics].[displayorder]>=0 
"
,
                                   BaseConfigs.GetTablePrefix,
                                   postTableId,
                                   postid.TrimEnd(
'
,
'
));
            
return
 sqlBuilder.ToString();
        }
        ....
}

 

 

       上面方法中的GetSearchPostContentSQL即是SPHINX查询对象的构造和执行过程了,大家可以参照SPHINX的官方文档或之前所说的那个中文文档来查询对应的语句语法。如果该方法执行正确,就会获取一个SQL语句,该语句与SQLSERVER进行全文检索时所调用的方法返回的SQL语句结果相同。
       不过上面代码中的这段代码要在这里解释一下,因为它与后面所讲述的“增量索引”是相互对应的:

ExpandedBlockStart.gif
foreach
 (
string
 keyword 
in
 Utils.SplitString(strKeyWord.ToString(), 
"
 
"
))
{
    cli.AddQuery(keyword, BaseConfigs.GetTablePrefix 
+
 
"
posts
"
 
+
 postTableId);
//
搜索主索引
    cli.AddQuery(keyword, BaseConfigs.GetTablePrefix 
+
 
"
posts
"
 
+
 postTableId 
+
 
"
_stem
"
);
//
搜索增量索引
}

 

          

 
      上面代码是执行查询时所使用的索引名称和关键字绑定,因为考虑到创建大数据量表索引时的时间会相对较长,所以这里引入了增量索引,也就是主索引中存储的是整个数据表中的索引信息(某时间段之前),而增量索引只保存指定条件(会在下文中说明)的"新记录(某时间段之后)"信息。我们可以让“创建主索引”的工作在一天中服务器最闲的时候来生成(比如凌晨4-5点钟),而增量索引每几分钟(甚至一分钟)生成一次。这样当查询时我们同时指定这两个索引来能实现“准实时”的查询效果了。
      除了在搜索时调用了该服务接口的相应方法,再有就是在创建或更新帖子信息时也调用了相应方法,比如创建帖子时(Discuz.Forum\Posts.cs):

ExpandedBlockStart.gif
///
 
<summary>
///
 创建帖子
///
 
</summary>
///
 
<param name="postInfo">
帖子信息类
</param>
///
 
<returns>
返回帖子id
</returns>
public
 
static
 
int
 CreatePost(PostInfo postInfo)
{
    
int
 pid 
=
 Data.Posts.CreatePost(postInfo, GetPostTableId(postInfo.Tid));
    
//
本帖具有正反方立场
    
if
 (postInfo.Debateopinion 
>
 
0
)
    {
        DebatePostExpandInfo dpei 
=
 
new
 DebatePostExpandInfo();
        dpei.Tid 
=
 postInfo.Tid;
        dpei.Pid 
=
 pid;
        dpei.Opinion 
=
 postInfo.Debateopinion;
        dpei.Diggs 
=
 
0
;
        Data.Debates.CreateDebateExpandInfo(dpei);
    }
    RemoveShowTopicCache(postInfo.Tid.ToString());
    
//
将数据同步到sphinx增量表中
    
if
 (pid 
>
 
0
 
&&
 EntLibConfigs.GetConfig() 
!=
 
null
 
&&
 EntLibConfigs.GetConfig().Sphinxconfig.Enable)
    {
        GetSphinxSqlService().CreatePost(GetPostTableName(), pid, postInfo.Tid, postInfo.Fid, postInfo.Posterid, postInfo.Postdatetime, postInfo.Title, postInfo.Message);              
    }
    
return
 pid;
}

 

    

      和更新帖子时:

ExpandedBlockStart.gif
///
 
<summary>
///
 更新指定帖子信息
///
 
</summary>
///
 
<param name="postsInfo">
帖子信息
</param>
///
 
<returns>
更新数量
</returns>
public
 
static
 
int
 UpdatePost(PostInfo postInfo)
{
    
if
 (postInfo 
==
 
null
 
||
 postInfo.Pid 
<
 
1
)
        
return
 
0
;
    RemoveShowTopicCache(postInfo.Tid.ToString());
    
//
将数据同步到sphinx增量表中
    
if
 (postInfo.Pid 
>
 
0
 
&&
 EntLibConfigs.GetConfig() 
!=
 
null
 
&&
 EntLibConfigs.GetConfig().Sphinxconfig.Enable)
    {
        GetSphinxSqlService().UpdatePost(GetPostTableName(), postInfo.Pid, postInfo.Tid, postInfo.Fid, postInfo.Posterid, postInfo.Postdatetime, postInfo.Title, postInfo.Message);              
    }
    
return
 Data.Posts.UpdatePost(postInfo, GetPostTableId(postInfo.Tid));
}

 

 

       到这时,架构中的Discuz!NT客户端部分甚本上就介绍完了。下一篇文章中将会介绍在服务器如果安装,配置SPHINX以及定时生成主和增量索引等工作。

 

      在中,介绍了Discuz!NT引入SPHINX的背景和相应的客户端的C#代码架构实现。今天这篇文章将会介绍如果在LINUX环境下安装配置SPHINX中文搜索工具,也就是服务器配置方案.

      目前在网络上可以找到的SPHINX中文插件主要有两个:

      1.coreseek: 
      2.sfc:

      其中的coreseek是目前对Discuz(PHP版)支持做的比较好的插件,它提供了相应的工具和源码包来尽可能简化sphinx的安装和配置。大家可从网上找到很多相关信息。

      今天本文要说的是使用sfc来安装配置sphinx,呵呵:)

       linux环境:centos 5.4 (需要安装gcc编译器来编译SPHINX源代码)

      因为SPHINX要访问MYSQL数据库,所以如果机器上没有安装MYSQL,可以使用下面命令进行安装:   

    [root@localhost ~]# yum install -y mysql mysql-devel 
    [root@localhost ~]# yum install -y automake autoconf

      

       下面开始安装SPHINX(sfc 插件):  

ExpandedBlockStart.gif
 [root@localhost ~]# cd /usr/local/src/ 
 [root@localhost src]# wget http://sphinx-for-chinese.googlecode.com/files/sphinx-for-chinese-0.9.9-r2117.tar.gz
 [root@localhost src]# tar zxvf sphinx-for-chinese-0.9.9-r2117.tar.gz  
 [root@localhost local]# cd sphinx-for-chinese-0.9.9-r2117 
 [root@localhost sphinx-for-chinese-0.9.9-r2117]# ./configure --prefix=/usr/local/sphinx --with-mysql #注意:这里sphinx已经默认支持了mysql,也可用--without-mysql来取消mysql
 [root@localhost sphinx-for-chinese-0.9.9-r2117]# make && make install # 其中的“警告”可以忽略

  

      到这里,基本就是完成了SPHINX的下载安装过程。

      下面开始下载中文字典文档: 

ExpandedBlockStart.gif
 [root@localhost ~]#cd /usr/local/sphinx/bin
 [root@localhost bin]# wget http://sphinx-for-chinese.googlecode.com/files/xdict_1.1.tar.gz
 [root@localhost bin]# tar zxvf xdict_1.1.tar.gz
 [root@localhost bin]#./mkdict xdict_1.1.txt xdict   #注:mkdict是sfc自有的

  

      这样就从xdict_1.1.txt文件生了xdict词典。

      因为要在SPHINX中使用增量索引,因为参照官方文档中提供的思路,在指定的MYSQL数据库中创建增量统计表: 

 #构造增量统计表
 
CREATE
 
TABLE
 sphcounter(counterid 
INTEGER
 
PRIMARY
 
KEY
 
NOT
 
NULL
,max_doc_id 
INTEGER
 
NOT
 
NULL
);

 

      接着就是创建Sphinx主索引文件、增量索引文件存放目录:

    [root@localhost ~]#mkdir /usr/local/sphinx/var/data/dnt_posts1/
    [root@localhost ~]#mkdir /usr/local/sphinx/var/data/dnt_posts1stemmed/

 

      然后编辑usr/local/sphinx/etc/sphinx.conf文件:

 [root@localhost bin] cd /usr/local/sphinx/etc/
 [root@localhost etc] vi sphinx.conf

 

       内容如下:

ExpandedBlockStart.gif
代码
source src1
{
     # known types are mysql, pgsql, mssql, xmlpipe, xmlpipe2, odbc
     type     = mysql
  sql_host    = 10.0.4.66  #mysql数据库链接参数
  sql_user    = root
  sql_pass    = root
  sql_db     = test
  sql_port    = 3306 #optional, default is 3306 
  #下面是获取MYSQL数据表的查询语句
  sql_query_pre = SET NAMES utf8 #加上这一行,以免因为编码不同造成中文乱码
  sql_query_pre    =replace into sphcounter select 1,MAX(pid) from dnt_posts1  
  sql_query   = SELECT pid,fid,title,message,poster,postdatetime from dnt_posts1 where pid 
<
=  (select 
max_doc_id from sphcounter where counterid
=1) 
  
sql_ranged_throttle 
= 0 
}
source src1throttled : src1
{
    sql_query_pre
=set 
names utf8
 #增量表所使用的查询语句,以获取最新的帖子信息
    sql_query
=SELECT 
pid,fid,title,message,poster,postdatetime FROM dnt_posts1 where pid 
>
 (select max_doc_id from sphcounter where counterid=1) 
}
index dnt_posts1
{
      # 放索引的目录
      path = /usr/local/sphinx/data/dnt_posts1
      docinfo            = extern
      #编码
      charset_type = utf-8
      #指定utf-8的编码表。注意:如使用这种方式,则sphinx会对中文进行单字切分,即进行字索引,若要使用中文分词,必须使用其他分词插件如 coreseek,sfc
   charset_table = U+FF10..U+FF19->0..9, 0..9, U+FF41..U+FF5A->a..z, U+FF21..U+FF3A->a..z,\
      A..Z->a..z, a..z, U+0149, U+017F, U+0138, U+00DF, U+00FF, U+00C0..U+00D6->U+00E0..U+00F6,\
      U+00E0..U+00F6, U+00D8..U+00DE->U+00F8..U+00FE, U+00F8..U+00FE, U+0100->U+0101, U+0101,\
      U+0102->U+0103, U+0103, U+0104->U+0105, U+0105, U+0106->U+0107, U+0107, U+0108->U+0109,\
      U+0109, U+010A->U+010B, U+010B, U+010C->U+010D, U+010D, U+010E->U+010F, U+010F,\
      U+0110->U+0111, U+0111, U+0112->U+0113, U+0113, U+0114->U+0115, U+0115, U+0116->U+0117,\
      U+0117, U+0118->U+0119, U+0119, U+011A->U+011B, U+011B, U+011C->U+011D, U+011D,\
      U+011E->U+011F, U+011F, U+0130->U+0131, U+0131, U+0132->U+0133, U+0133, U+0134->U+0135,\
      U+0135, U+0136->U+0137, U+0137, U+0139->U+013A, U+013A, U+013B->U+013C, U+013C,\
      U+013D->U+013E, U+013E, U+013F->U+0140, U+0140, U+0141->U+0142, U+0142, U+0143->U+0144,\
      U+0144, U+0145->U+0146, U+0146, U+0147->U+0148, U+0148, U+014A->U+014B, U+014B,\
      U+014C->U+014D, U+014D, U+014E->U+014F, U+014F, U+0150->U+0151, U+0151, U+0152->U+0153,\
      U+0153, U+0154->U+0155, U+0155, U+0156->U+0157, U+0157, U+0158->U+0159, U+0159,\
      U+015A->U+015B, U+015B, U+015C->U+015D, U+015D, U+015E->U+015F, U+015F, U+0160->U+0161,\
      U+0161, U+0162->U+0163, U+0163, U+0164->U+0165, U+0165, U+0166->U+0167, U+0167,\
      U+0168->U+0169, U+0169, U+016A->U+016B, U+016B, U+016C->U+016D, U+016D, U+016E->U+016F,\
      U+016F, U+0170->U+0171, U+0171, U+0172->U+0173, U+0173, U+0174->U+0175, U+0175,\
      U+0176->U+0177, U+0177, U+0178->U+00FF, U+00FF, U+0179->U+017A, U+017A, U+017B->U+017C,\
      U+017C, U+017D->U+017E, U+017E, U+0410..U+042F->U+0430..U+044F, U+0430..U+044F,\
      U+05D0..U+05EA, U+0531..U+0556->U+0561..U+0586, U+0561..U+0587, U+0621..U+063A, U+01B9,\
      U+01BF, U+0640..U+064A, U+0660..U+0669, U+066E, U+066F, U+0671..U+06D3, U+06F0..U+06FF,\
      U+0904..U+0939, U+0958..U+095F, U+0960..U+0963, U+0966..U+096F, U+097B..U+097F,\
      U+0985..U+09B9, U+09CE, U+09DC..U+09E3, U+09E6..U+09EF, U+0A05..U+0A39, U+0A59..U+0A5E,\
      U+0A66..U+0A6F, U+0A85..U+0AB9, U+0AE0..U+0AE3, U+0AE6..U+0AEF, U+0B05..U+0B39,\
      U+0B5C..U+0B61, U+0B66..U+0B6F, U+0B71, U+0B85..U+0BB9, U+0BE6..U+0BF2, U+0C05..U+0C39,\
      U+0C66..U+0C6F, U+0C85..U+0CB9, U+0CDE..U+0CE3, U+0CE6..U+0CEF, U+0D05..U+0D39, U+0D60,\
      U+0D61, U+0D66..U+0D6F, U+0D85..U+0DC6, U+1900..U+1938, U+1946..U+194F, U+A800..U+A805,\
      U+A807..U+A822, U+0386->U+03B1, U+03AC->U+03B1, U+0388->U+03B5, U+03AD->U+03B5,\
      U+0389->U+03B7, U+03AE->U+03B7, U+038A->U+03B9, U+0390->U+03B9, U+03AA->U+03B9,\
      U+03AF->U+03B9, U+03CA->U+03B9, U+038C->U+03BF, U+03CC->U+03BF, U+038E->U+03C5,\
      U+03AB->U+03C5, U+03B0->U+03C5, U+03CB->U+03C5, U+03CD->U+03C5, U+038F->U+03C9,\
      U+03CE->U+03C9, U+03C2->U+03C3, U+0391..U+03A1->U+03B1..U+03C1,\
      U+03A3..U+03A9->U+03C3..U+03C9, U+03B1..U+03C1, U+03C3..U+03C9, U+0E01..U+0E2E,\
      U+0E30..U+0E3A, U+0E40..U+0E45, U+0E47, U+0E50..U+0E59, U+A000..U+A48F, U+4E00..U+9FBF,\
      U+3400..U+4DBF, U+20000..U+2A6DF, U+F900..U+FAFF, U+2F800..U+2FA1F, U+2E80..U+2EFF,\
      U+2F00..U+2FDF, U+3100..U+312F, U+31A0..U+31BF, U+3040..U+309F, U+30A0..U+30FF,\
      U+31F0..U+31FF, U+AC00..U+D7AF, U+1100..U+11FF, U+3130..U+318F, U+A000..U+A48F,\
      U+A490..U+A4CF
      #简单分词,只支持0和1,如果要搜索中文,请指定为1
      ngram_len = 1
      #需要分词的字符,如果要搜索中文,去掉前面的注释
      ngram_chars = U+4E00..U+9FBF, U+3400..U+4DBF, U+20000..U+2A6DF, U+F900..U+FAFF,\
     U+2F800..U+2FA1F, U+2E80..U+2EFF, U+2F00..U+2FDF, U+3100..U+312F, U+31A0..U+31BF,\
     U+3040..U+309F, U+30A0..U+30FF, U+31F0..U+31FF, U+AC00..U+D7AF, U+1100..U+11FF,\
     U+3130..U+318F, U+A000..U+A48F, U+A490..U+A4CF
      source = src1
      min_infix_len  = 1      
      min_word_len  = 1  
   #加上这个选项,则会对每个中文,英文字词进行分割,速度会慢
   #ngram_chars = U+4E00..U+9FBF, U+3400..U+4DBF, U+20000..U+2A6DF, U+F900..U+FAFF,\
   #U+2F800..U+2FA1F, U+2E80..U+2EFF, U+2F00..U+2FDF, U+3100..U+312F, U+31A0..U+31BF,\
   #U+3040..U+309F, U+30A0..U+30FF, U+31F0..U+31FF, U+AC00..U+D7AF, U+1100..U+11FF,\
   #U+3130..U+318F, U+A000..U+A48F, U+A490..U+A4CF
      chinese_dictionary = /usr/local/sphinx/bin/xdict
}
index dnt_posts1stemmed : dnt_posts1
{
    source                  =src1throttled
    path            = /usr/local/sphinx/data/dnt_posts1stemmed
}
indexer
{}
searchd
{
   listen     = 10.0.4.66:3312
   pid_file   = /usr/local/sphinx/log/searchd.pid
   read_timeout  = 30 #请求超时
   client_timeout  = 300 
   max_children = 30 #同时可执行的最大searchd 进程数
   preopen_indexes  = 1
   max_packet_size  = 128M
   max_matches = 1000 #查询结果的最大返回数
   max_filters   = 256
   max_filter_values = 4096
   read_buffer   = 4096K
}

 

     

       其中的searchd节点下listen对应的是就服务器SPHINX守护进程的地址和端口信息及其它进程配置参数(详见sphinx官方示例文档)  

      

 

      对应上面的配置文件,下面是sfc官方的说明:

      charset_type = utf-8 #其中charst_type选择utf-8即可

      chinese_dictionary = /path/to/xdict #chinese_dictionary是指定分词词典的选项,包括路径和文件名,这样中文支持就可以了
      同时当chinese_dictionary和utf-8的ngram选项同时出现时,会优先使用sphinx-for-chinese的中文支持方法。如果要使用ngram方法,将chinese_dictionary选项去掉即可。

      如果配置正确,就可以使用下面命令行来创建索引了: 

 [root@localhost sphinx]# bin/indexer -c etc/sphinx.conf dnt_posts1  #建立索引文件的命令,目前该分表中存在26w条帖子信息

 

      信息显示: 

ExpandedBlockStart.gif 
 Sphinx 0.9.9-release (r2117)
 Copyright (c) 2001-2009, Andrew Aksyonoff
 using config file 'etc/sphinx.conf'...
 indexing index 'dnt_posts1'...
 collected 99820 docs, 17.6 MB
 sorted 29.8 Mhits, 97.4% done
 total 99820 docs, 17553938 bytes
 total 35.498 sec, 494498 bytes/sec, 2811.95 docs/sec
 WARNING: no such index '-rotate', skipping.
 total 294 reads, 0.220 sec, 432.5 kb/call avg, 0.7 msec/call avg
 total 312 writes, 1.372 sec, 956.0 kb/call avg, 4.3 msec/call avg

  

        查询:

 [root@localhost sphinx]# bin/search -c etc/sphinx.conf hello # 查询hello

  

      信息显示:

ExpandedBlockStart.gif
[root@localhost sphinx]# bin/search -c etc/sphinx.conf hello
Sphinx 0.9.9-release (r2117)
Copyright (c) 2001-2009, Andrew Aksyonoff
using config file 'etc/sphinx.conf'...
index 'dnt_posts20': query 'hello ': returned 12 matches of 12 total in 0.001 sec
displaying matches:
1. document=5206761, weight=1, tid=312375, fid=4, posterid=97258, postdatetime=Mon Jan  2 17:30:00 2006
2. document=5213543, weight=1, tid=312709, fid=4, posterid=30374, postdatetime=Tue Jan  3 01:43:00 2006
3. document=5237575, weight=1, tid=314170, fid=79, posterid=54334, postdatetime=Sat Jan  7 19:55:00 2006
4. document=5253361, weight=1, tid=314961, fid=12, posterid=2587, postdatetime=Mon Jan  9 13:22:00 2006
5. document=5258138, weight=1, tid=315239, fid=78, posterid=52580, postdatetime=Wed Jan 11 17:03:00 2006
6. document=5258160, weight=1, tid=315239, fid=78, posterid=39959, postdatetime=Thu Jan 12 19:49:00 2006
7. document=5259929, weight=1, tid=315343, fid=12, posterid=55028, postdatetime=Wed Jan 25 17:48:00 2006
8. document=5262286, weight=1, tid=315516, fid=81, posterid=57720, postdatetime=Wed Jan 11 01:00:00 2006
9. document=5264041, weight=1, tid=315612, fid=18, posterid=96303, postdatetime=Thu Jan 12 13:00:00 2006
10. document=5268527, weight=1, tid=315837, fid=78, posterid=26965, postdatetime=Thu Jan 12 12:47:00 2006
11. document=5268541, weight=1, tid=315837, fid=78, posterid=48761, postdatetime=Thu Jan 12 18:54:00 2006
12. document=5274196, weight=1, tid=316220, fid=12, posterid=50496, postdatetime=Fri Jan 13 22:22:00 2006
words:
1. 'hello': 12 documents, 16 hits
index 'dnt_posts20_stem': query 'hello ': returned 5 matches of 5 total in 0.000 sec
displaying matches:
1. document=5300417, weight=1, tid=317247, fid=4, posterid=97227, postdatetime=Thu Jan  1 08:33:26 1970
2. document=5300424, weight=1, tid=317247, fid=4, posterid=31887, postdatetime=Thu Jan  1 08:33:26 1970
3. document=5307959, weight=1, tid=317654, fid=120, posterid=18760, postdatetime=Thu Jan  1 08:33:26 1970
4. document=5308076, weight=1, tid=317662, fid=120, posterid=18760, postdatetime=Thu Jan  1 08:33:26 1970
5. document=5308079, weight=1, tid=317662, fid=120, posterid=18760, postdatetime=Thu Jan  1 08:33:26 1970
words:
1. 'hello': 5 documents, 10 hits

      

       开启守护进程: 

 [root@localhost sphinx]# bin/searchd -c etc/sphinx.conf 

 

       信息显示: 

 Sphinx 0.9.9-release (r2117)
 Copyright (c) 2001-2009, Andrew Aksyonoff
 using config file 'etc/sphinx.conf'...
 listening on 10.0.4.66:3312
 You have new mail in /var/spool/mail/root

  

      之前提到,客户端会对主索引和增量索引同时进行查询,而主索引和增量索引会被做了定时任务方式进行执行。那么接下来就是做这一部分的工作:

      创建两个shell脚本,分别用来创建主索引和创建增量索引。

   1.创建主索引更新脚本,build_main_index.sh:      

vi /usr/local/sphinx/bin/build_main_index.sh

      

      输入以下内容(双击打开):   

    #!/bin/sh
    /usr/local/shpinx/bin/indexr --rotate dnt_posts1
    sleep 1
    #清空搜索日志
     :/>/usr/local/sphinx/var/log/query.log
    :/>/usr/local/sphinx/var/log/searchd.log  

    

     2.赋予主索引更新脚本可执行权限:     

 chmod +x /usr/local/sphinx/bin/build_main_index.sh

    

     3.每天凌晨定时重建主索引:    

 crontab -e

       增加以下内容:    

  #每天凌晨4点19分重建一次搜索引擎的主索引
  19 4 * * * /bin/sh /usr/local/sphinx/bin/build_main_index.sh

    

      4.创建脚本build_delta_index.sh:      

vi /usr/local/sphinx/bin/build_delta_index.sh

     

       输入以下内容(双击打开):

  #!/bin/sh
  /usr/local/sphinx/bin/indexer --rotate dnt_posts1stemmed

  

    5.赋予增量索引更新脚本可执行权限:    

 chmod +x /usr/local/sphinx/bin/build_delta_index.sh

 

    6.每3分钟自动重建一次搜索引擎的增量索引:      

crontab -e

 

      增加以下内容:      

  #每3分钟自动重建一次搜索引擎的增量索引
  0-57/3 * * * * /bin/sh /usr/local/sphinx/bin/build_delta_index.sh

    

    7.配置服务器开机启动时需要自动执行的命令      

vi /etc/rc.local

 

   内容:  

ExpandedBlockStart.gif
 ulimit -SHn 500000
 /usr/bin/nohup /bin/sh /usr/local/sphinx/bin/build_main_index.sh 2>
&1
 > /dev/null &
 /bin/sh /usr/local/sphinx/bin/build_delta_index.sh  2>
&1
 > /dev/null
 /usr/local/sphinx/bin/searchd

 

      这样在服务端的配置工作就告一段落了。

      当然,对于以前使用过Discuz!NT的用户,我们提供了一个同步工具来将已有的帖子分表同步的指定的MYSQL数据库里以便让SPHINX来访问。如下: 

     

      这样就解决了已有数据该如何被索引的问题,剩下的就是要不断的修改sphinx.conf文件以添加新的索引和增量索引了(因为我们使用了帖子分表功能,会在帖子表记录达到一定数量时创建新的分表,这样就可以保持当前所使用的帖子分表记录不会过于庞大,从而影响数据库查询效率)和在相应的sh文件中添加对新索引的定时创建命令了。

      当然,SPHINX还支持分布式检索服务,不过因为眼下的架构未用到,所以就不多做说明了,大家可以去网上搜索相关信息即可。

     

       原文链接:

       BLOG:

       作者:daizhj,代震军

 

      参考链接:

      Sphinx中文指南

      sphinx_doc_zhcn_0.9-中文手册 
      亿级数据的高并发通用搜索引擎架构设计
      sphinx-for-chinese :
      coreseek: 

分类:

转载于:https://www.cnblogs.com/fx2008/archive/2011/12/29/2305691.html

你可能感兴趣的文章
Elasticsearch——Search的基本介绍
查看>>
Vue v-bind的使用
查看>>
第 22 章 Beta
查看>>
Linux 监视文件、文件夹改动
查看>>
[Erlang 0079] RabbitMQ 初探
查看>>
36.5. height / width
查看>>
树莓派蜜罐节点部署实战
查看>>
交换知识 VLAN VTP STP 单臂路由
查看>>
svn 回滚到上一个版本shell 脚本
查看>>
UID 修改 & UID 锁死修复
查看>>
动手实践虚拟网络 - 每天5分钟玩转 OpenStack(10)
查看>>
(转) Deep Learning Resources
查看>>
Node.js 开发模式(设计模式)
查看>>
vs生成命令和属性的宏
查看>>
【Python】supervisor 工具介绍
查看>>
【MySQL】浅谈一致性读
查看>>
浅谈嵌入式软件的未来发展
查看>>
8.4. Socket 方式
查看>>
对于技术焦虑的一点想法
查看>>
Spring3 MVC请求参数获取的几种场景
查看>>