一、问题的引入
 
在sphinx应用中,需要对数据进行复杂的条件过滤,刷选出我们需要的数据。这个过程,等同于mysql查询中的where条件。
 
但sphinx本身的filter并不能支持复杂的逻辑组合运算,各个过滤条件之间只能进行AND操作,连OR操作都不支持。
 
为了解决这个问题,之前我们是在建立索引的时候,从源数据库取出数据建立索引的时候,利用mysql的sql语句,在数据导入的时候就要把逻辑摊开。
这样会带来很多问题:
1)sphinx配置文件复杂,变动不灵活,当业务发生变化的时候,需要修改后台的sphinx配置文件,重建索引;
2)没法做到业务表现和数据分离,前后台耦合严重;
3)从源db获取数据的sql语句复杂,不方便维护调整,同时增加建立索引的时间
4)sphinx的开发维护人员,必须非常清楚业务的特点才能实现,不利于各人的分工协作
5)当逻辑实在太复杂,数据导入的时候没法将逻辑摊开的时候,采用这种方式,业务就没法实现了
 
 
二、新的解决方案
新的解决方案,利用SetSelect()和SetFilter()这两个api,对sphinx的参数进行逻辑操作来实现。
下面根据例子来说明。
 
1. 准备测试环境和数据
 
创建表格和插入数据
CREATE TABLE `t_test_filter` (
  `Fcommodity_id` bigint(20) unsigned NOT NULL DEFAULT '0',
  ` FUserId` int(10) unsigned NOT NULL DEFAULT '0',
  ` FUserName` varchar(32) NOT NULL DEFAULT '',
  `Fshopid` bigint(20) unsigned NOT NULL DEFAULT '0',
  `Ftitle` varchar(60) NOT NULL DEFAULT '',
  `FProperty` int(10) unsigned NOT NULL DEFAULT '0',
  `FTime` int(10) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`Fcommodity_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
 
 
创建sphinxSE的表格
CREATE TABLE `t_test_filter_sphinxSE` (
  `id` bigint(20) unsigned NOT NULL,
  `weight` int(11) DEFAULT '1',
  `query` varchar(3072) NOT NULL,
  `total_found` int(11) DEFAULT '0',
  `total_match` int(11) DEFAULT '0',
  `query_time` int(11) DEFAULT '0',
  ` FUserId` int(10) unsigned DEFAULT '0',
  `Fshopid` bigint(20) unsigned NOT NULL DEFAULT '0',
  `FProperty` int(10) unsigned NOT NULL DEFAULT '0',
  `FTime` int(10) unsigned NOT NULL DEFAULT '0',
  KEY `query` (`query`(1536))
) ENGINE=SPHINX DEFAULT CHARSET=gbk CONNECTION='sphinx://localhost:9412'
 
插入测试数据
insert into t_test_filter values(4567,123,"test qq nick", 1234567,"title name",2324354,9876);
insert into t_test_filter values(2,34,"nick name", 4545,"title name",67,40);
insert into t_test_filter values(66,55,"test3 qq3 nick3", 22,"title3 name3 ",88,77);
insert into t_test_filter values(767,234,"test3 qq nick", 3433,"title3 name3 ",342342,89340);
insert into t_test_filter values(4545,123,"test qq nick", 1234567,"title name",2324354,9876);
insert into t_test_filter values(4546,778,"test qq nick", 1234567,"title name",2324354,9876);
 
2. 使用举例
 
这里用sphinxSE的接口,举2个例子来说明这种方法:
 
(1)查询词是nick,满足条件 FUserId=34 || Fshopid = 1234567;
通过sphinxSE测试查询
select * from t_test_filter_sphinxSE where query="nick;select=IF( FUserId=34,1,0) + IF(Fshopid=1234567,10,0) as match_qq; filter= match_qq, 1,10,11";
 
(2)查询词是nick,满足条件 FUserId=34 || (Fshopid = 1234567 && FUserId=778);
select * from t_test_filter_sphinxSE where query="nick;select=IF( FUserId=34,1,0) + IF(Fshopid=1234567,10,0) + IF( FUserId=778,100,0) as match_qq; filter= match_qq, 1,110,111";
 
为了减少组合导致的过滤条件太多,可以使用诸如下面这种逻辑运算来简化
 
select * from t_test_filter_sphinxSE where query="nick;select=IF( FUserId=34,1,0) OR ( IF(Fshopid=1234567,1,0) AND IF( FUserId=778,1,0)) as match_qq; filter= match_qq, 1";
 

这两条语句的作用相同。

 
其他复杂的查询,可以按照这个原理组合实现。
 
原理:
 
1. 函数IF()的说明:它接受3个参数,检查第一个参数是否为0.0,若非零则返回第二个参数,为零时则返回第三个参数;
2. 上面的语法主要是query里面的语句。
(1) 第一个词是nick,表示需要查询到关键词。
(2)select语句,这个等同于api接口中的SetFilter()。这个是从配置文件的sql_attr_xxxx中,过滤返回的数据。select计算的结果,保存在某个变量名(match_qq)中。这里的计算支持+, -, *, /, <, > <=, >=, =, <>等操作符。
(3)filter语句,这个等同于api接口中的SetFilter()。根据select的结果,用filter过滤。不同的查询条件可以得到不同的组合。这样就可以支持非常复杂的查询过滤条件了。
 
其他接口可以类似,比如c-api和php的接口,可以使用SetSelect()和SetFilter()这两个api实现。
 
3. 优点和局限
1.在SetSelect()中支持比较负责数学运算和一些逻辑组合,可以灵活实现各种逻辑;
2.业务开发人员和sphinx的运维配置人员,可以分开独立
3.版本限制
(1) sphinxSE的接口,需要在coreseek4.0.1或者sphinx0.9.9rc1以上的版本才支持。
(2) c-api和php的接口,在coreseek3.2.14应该已经支持,他已经提供了SetSelect()和SetFilter()这两个api,但我没有实试过。
 
 
 
三、附录
这里附上sphinx配置文件,以便大家更好的分析和测试
 
# file: t_test_filter.conf
 
source t_test_filter
{
        type                                    = mysql
 
        sql_host                                = localhost
        sql_user                                = xxxx
        sql_pass                                = xxx
        sql_db                                  = test
        sql_port                                = 3306
 
        sql_query    =  SELECT Fcommodity_id, FUserId, FUserName,Fshopid, Ftitle, FProperty,FTime from t_test_filter
 
        sql_attr_uint                   = FUserId
        sql_attr_bigint                   = Fshopid
        sql_attr_uint                   = FProperty
        sql_attr_uint                   = FTime
}
 
index t_test_filter
{
        source                  = t_test_filter
        path                    = /usr/local/coreseek/var/data/t_test_filter
        docinfo                 = extern
        mlock                   = 0
        morphology              = none
        exceptions              = /usr/local/coreseek/var/exceptions.txt
        min_word_len            = 1
        charset_type = zh_cn.gbk
        charset_dictpath = /usr/local/coreseek/dict
        ngram_len                               = 1
        ngram_chars                     = U+3000..U+2FA1F
        html_strip                              = 0
        blend_mode              = trim_none
}
 
 
 
#############################################################################
## indexer settings
#############################################################################
 
indexer
{
        # memory limit, in bytes, kiloytes (16384K) or megabytes (256M)
        # optional, default is 32M, max is 2047M, recommended is 256M to 1024M
        mem_limit                       = 40M
 
        # maximum IO calls per second (for I/O throttling)
        # optional, default is 0 (unlimited)
        #
        # max_iops                      = 40
 
        # maximum IO call size, bytes (for I/O throttling)
        # optional, default is 0 (unlimited)
        #
        # max_iosize            = 1048576
 
        # maximum xmlpipe2 field length, bytes
        # optional, default is 2M
        #
        # max_xmlpipe2_field    = 4M
 
        # write buffer size, bytes
        # several (currently up to 4) buffers will be allocated
        # write buffers are allocated in addition to mem_limit
        # optional, default is 1M
        #
        write_buffer            = 1M
}
 
#############################################################################
## searchd settings
#############################################################################
 
searchd
{
        # hostname, port, or hostname:port, or /unix/socket/path to listen on
        # multi-value, multiple listen points are allowed
        # optional, default is 0.0.0.0:9312 (listen on all interfaces, port 9312)
        #
        # listen                                = 127.0.0.1
        # listen                                = 192.168.0.1:9312
        listen                          = 9412
        # listen                                = /var/run/searchd.sock
        listen = localhost:9406:mysql41
 
        binlog_path = /usr/local/coreseek/var/data
 
        # log file, searchd run info is logged here
        # optional, default is 'searchd.log'
        log                                     = /usr/local/coreseek/var/log/searchd_9412.log
 
        # query log file, all search queries are logged here
        # optional, default is empty (do not log queries)
        query_log                       = /usr/local/coreseek/var/log/query_9412.log
 
        # client read timeout, seconds
        # optional, default is 5
        read_timeout            = 5
 
        # request timeout, seconds
        # optional, default is 5 minutes
        client_timeout          = 300
 
        # maximum amount of children to fork (concurrent searches to run)
        # optional, default is 0 (unlimited)
        max_children            = 30
 
        # PID file, searchd process ID file name
        # mandatory
        pid_file                        = /usr/local/coreseek/var/log/searchd_9412.pid
 
        # max amount of matches the daemon ever keeps in RAM, per-index
        # WARNING, THERE'S ALSO PER-QUERY LIMIT, SEE SetLimits() API CALL
        # default is 1000 (just like Google)
        max_matches                     = 1000000
 
        # seamless rotate, prevents rotate stalls if precaching huge datasets
        # optional, default is 1
        seamless_rotate         = 1
 
        # whether to forcibly preopen all indexes on startup
        # optional, default is 0 (do not preopen)
        preopen_indexes         = 0
 
        # whether to unlink .old index copies on succesful rotation.
        # optional, default is 1 (do unlink)
        unlink_old                      = 1
 
        # attribute updates periodic flush timeout, seconds
        # updates will be automatically dumped to disk this frequently
        # optional, default is 0 (disable periodic flush)
        #
        # attr_flush_period     = 900
 
        # instance-wide ondisk_dict defaults (per-index value take precedence)
        # optional, default is 0 (precache all dictionaries in RAM)
        #
        # ondisk_dict_default   = 1
 
        # MVA updates pool size
        # shared between all instances of searchd, disables attr flushes!
        # optional, default size is 1M
        mva_updates_pool        = 1M
 
        # max allowed network packet size
        # limits both query packets from clients, and responses from agents
        # optional, default size is 8M
        max_packet_size         = 8M
 
        # crash log path
        # searchd will (try to) log crashed query to 'crash_log_path.PID' file
        # optional, default is empty (do not create crash logs)
        #
        # crash_log_path                = /usr/local/coreseek/var/log/crash
 
        # max allowed per-query filter count
        # optional, default is 256
        max_filters                     = 256
 
        # max allowed per-filter values count
        # optional, default is 4096
        max_filter_values       = 4096
 
        # socket listen queue length
        # optional, default is 5
        #
        # listen_backlog                = 5
 
        # per-keyword read buffer size
        # optional, default is 256K
        #
        # read_buffer                   = 256K
 
        # unhinted read size (currently used when reading hits)
        # optional, default is 32K
        #
        # read_unhinted         = 32K
}
 
# --eof--

在sphinx中应用复杂过滤条件的更多相关文章

  1. 如何在K3 WISE BOS集成开发工具中自定义字段过滤条件

    1.结论 对于输入过滤条件后BOS报“列名不正确”的过滤条件,要在列名前增加x2标识 无效的过滤 FNumber ,,,,,) 正确的过滤 x2.FNumber ,,,,,) 2.完全可以不看的探索过 ...

  2. SQL语句中过滤条件放在on、where、having的区别和联系

    摘要:SQL语句中,过滤条件放在不同筛选器on.where和having的区别和联系. 综述   在<SQL语句中过滤条件放在on和where子句中的区别和联系>中,介绍了多表关联SQL语 ...

  3. SQL优化 查询语句中,用 inner join 作为过滤条件和用where作为过滤条件的区别

    前段时间遇到一个存储过程,参数之一是一个字符串,在存储过程中,把字符串拆分成一个临时表之后存为一个key值的临时表,作为其中一个查询条件, 逻辑实现上有两种处理方式 insert into #t se ...

  4. k3 cloud中提示总账期末结账提示过滤条件太长,请修改此过滤条件

    k3 cloud中提示总账期末结账提示过滤条件太长,请修改此过滤条件,如下图所示: 处理方法: 请尝试系统配置文件common.config中将如附件所示的参数值改大,建议值为2000,并在系统清理缓 ...

  5. SQL语句中过滤条件放在on和where子句中的区别和联系

    摘要: 介绍在多表关联SQL语句中,过滤条件放在on和where子句中的区别--inner join中没区别,外连接就不一样. 综述   蚂蚁金服的一道SQL面试题如下:SQL语句中,过滤条件放在on ...

  6. .NET深入实战系列--EF到底怎么写过滤条件

    本文唯一访问地址:http://www.cnblogs.com/yubaolee/p/DynamicLinq.html 对于系统开发来说,按不同字段进行过滤查询是一种常见的需求.在EF中通常的做法是: ...

  7. 自定义 Azure Table storage 查询过滤条件

    本文是在Azure Table storage 基本用法一文的基础上,介绍如何自定义 Azure Table storage 的查询过滤条件.如果您还不太清楚 Azure Table storage ...

  8. 在DataTable中执行DataTable.Select("条件")返回DataTable;

    转:http://blog.csdn.net/hcf_force/article/details/7779062 1.在DataTable中执行DataTable.Select("条件&qu ...

  9. WireShark系列: 使用WireShark过滤条件抓取特定数据流(zz)

    应用抓包过滤,选择Capture | Options,扩展窗口查看到Capture Filter栏.双击选定的接口,如下图所示,弹出Edit Interface Settints窗口. 下图显示了Ed ...

随机推荐

  1. 线上redis服务内存异常分析。

    项目中,新增了一个统计功能,用来统计不同手机型号的每天访问pv,看了下redis2.6有个setbit的功能,于是打算尝尝鲜把 redis从2.4更新到了2.6 因为是租了vps.服务器的内存只有4g ...

  2. ubuntu myeclipse 启动时提示 A Java Runtime Environment (JRE) or Java Development Kit (JDK) must be avail ....

    jdk已经安装过但是启动eclipse时提示“A Java Runtime Environment (JRE) or Java Development Kit (JDK) must be avail  ...

  3. 编码的UI测试项目——Visual Studio 2013

    今天实现了一次编码的UI测试项目,以下是我进行测试的过程: 1.新建测试项目 在visual studio中(我用的版本是2013 update2)点击文件->新建->项目,选择“编码的U ...

  4. 高级正则表达式技术(Python版)

    正则表达式是从信息中搜索特定的模式的一把瑞士军刀.它们是一个巨大的工具库,其中的一些功能经常被忽视或未被充分利用.今天我将向你们展示一些正则表达式的高级用法. 举个例子,这是一个我们可能用来检测电话美 ...

  5. JavaScript Type Conversion

    Data Types 5 Data Types string, number, boolean, object, function 3 Object Types object, array, date ...

  6. Markdown 是什么?

    这是一篇 Markdown 学习笔记,简要记录常用 Markdown 语法. Markdown 是什么? Markdown 是一种轻量级标记语言,创始人为约翰·格鲁伯(John Gruber)和亚伦· ...

  7. 《Linux命令行与shell脚本编程大全》 第一、二章 学习笔记

    第一章:初识Linux shell Linux内核负责以下4个主要功能: 1.系统内存管理 2.软件程序管理 3.硬件设备管理 4.文件系统管理 1.系统内存管理 内核不仅管理服务器上的可用物理内存, ...

  8. 判断浏览器是IE的几种方式

    <script> if(!+[1,])alert("这是ie浏览器"); else alert("这不是ie浏览器"); </script&g ...

  9. phpcms学习总结

    文件目录结构 根目录 | – api 接口文件目录 | – caches 缓存文件目录 | – configs 系统配置文件目录 | – caches_* 系统缓存目录 | – phpcms phpc ...

  10. Mapreduce执行过程分析(基于Hadoop2.4)——(二)

    4.3 Map类 创建Map类和map函数,map函数是org.apache.hadoop.mapreduce.Mapper类中的定义的,当处理每一个键值对的时候,都要调用一次map方法,用户需要覆写 ...