在CMS开发中,经常会有类似这样的需求:

提问——回答模式,最经典的例子就是百度提问。

提问者提出问题,由其他人回答,其他人可以是用户,也可以是服务商。

在这个模式中,如何充分利用历史数据是最关键的技术。很多时候,由于客户不擅长使用搜索功能,一上来就提问,而这些问题往往早已经有近乎完美的答案,但没有充分利用。这样一来,不仅加大了劳动量,又增加了数据冗余。

如果在提问的时候能充分调动历史数据,提交问题之前先看看历史问题能不能解决客户疑问,解决了,最好不过,解决不了,再提交。百度提问就是采用的这种方案:

模式固然好,可怎么实现就有些困难了,毕竟这是百度作为搜索引擎的看家本领。

从上图可以看出“CSDN网站如何注册用户”这句话被拆成了N个词,然后分开去数据库中匹配,为什么?因为直接去匹配“CSDN网站如何注册用户”这句话,汉语博大精深,稍微变动一下:“如何在CSDN网站注册用户”,意思完全一样,但直接匹配绝对匹配不到!

因此,我们需要把一句话拆分成词组,这个在网上有现成的组件,比如“庖丁解牛”等,它们大多数是免费开源的。拆成词组之后,应该还要有一个关键词筛选词库,用这个词库确定出有效的词组,比如上图中,“CSDN”、“注册”、“用户”是有效的,而“网站”显然没有匹配,因为它在这句话中没有实际意义。

有点跑题了,拆词、选词不是本文的重点,但却是本文的前提。拿到关键词之后,怎么去数据库中匹配呢?

大家都知道T-SQL中的LIKE语句,通过类似LIKE “%abc%”这样的语法,可以进行模糊匹配,但是它仅仅能进行一次模糊匹配。举个例子:

假如我们确定了a,b,c三个关键词,要查找的记录当然是匹配的越多越好,于是可以这样写:LIKE “%a%b%c%”,这样匹配出的就是包含a,b,c三个关键词的记录,但是如果根本没有包含这三个关键词的记录,最多只有包含两个的,甚至是只包含一个,那么如何写LIKE语句呢?这样LIKE “%a%b%”?这样LIKE “%a%c%”?这样LIKE “%b%c%”?这样LIKE “%a%”?这样LIKE “%b%”?这样LIKE “%c%”?

显然,需要判断的情况太多,简单的LIKE语句已经无法满足需求。需要注意的是,千万不要试图选出范范的记录,返回到程序中去处理,在程序中处理虽然简单,但是范范的记录,在一个中型系统中,往往能达到千万级别,这么大的数据量,从数据库返回到程序,无疑会给服务器造成相当大的压力。

经过探索,本小菜总结了一个比较简单的方法,暂且称为“LIKE语句多条件贪婪匹配算法”。

         算法思想:先用LIKE选出每一组符合一个条件的记录,只选择表的主键。然后把这些记录合并在一起,通过主键分组、统计数量,数量最多的,也就是匹配最多的,最后根据数量降序排序,越靠上的记录,匹配的越多。选出匹配的多的记录主键字段,再根据主键去表中选出内容即可。

为了方便大家使用,已经把算法封装成存储过程(直接把下边代码在查询分析器中执行即可)。

存储过程(函数)如下:

GO
CREATE function Get_StrArrayLength
(
@str varchar(1024), --要分割的字符串
@split varchar(10) --分隔符号
)
returns int
as
begin
declare @location int
declare @start int
declare @length int
set @str=ltrim(rtrim(@str))
set @location=charindex(@split,@str)
set @length=1
while @location<>0
begin
set @start=@location+1
set @location=charindex(@split,@str,@start)
set @length=@length+1
end
return @length
end
GO
CREATE function Get_StrArrayStrOfIndex
(
@str varchar(1024), --要分割的字符串
@split varchar(10), --分隔符号
@index int --取第几个元素
)
returns varchar(1024)
as
begin
declare @location int
declare @start int
declare @next int
declare @seed int
set @str=ltrim(rtrim(@str))
set @start=1
set @next=1
set @seed=len(@split)
set @location=charindex(@split,@str)
while @location<>0 and @index>@next
begin
set @start=@location+@seed
set @location=charindex(@split,@str,@start)
set @next=@next+1
end
if @location =0 select @location =len(@str)+1 --这儿存在两种情况:1、字符串不存在分隔符号 2、字符串中存在分隔符号,跳出while循环后,@location为0,那默认为字符串后边有一个分隔符号。
return substring(@str,@start,@location-@start)
end
GO
CREATE PROCEDURE proc_Common_SuperLike
--要查询的表的主键字段名称
@primaryKeyName varchar(999),
--要查询的表名
@talbeName varchar(999),
--要查询的表的字段名称,即内容所在的字段
@contentFieldName varchar(999),
--查询记录的个数(TOP *),匹配的个数越多,排名越靠前
@selectNumber varchar(999),
--匹配字符分隔标记
@splitString varchar(999),
--匹配字符组合字符串
@words varchar(999) AS
declare @sqlFirst varchar(999)
declare @sqlCenter varchar(999)
declare @sqlLast varchar(999)
BEGIN
set @sqlCenter=''
declare @next int
set @next=1
while @next<=dbo.Get_StrArrayLength(@words,@splitString)
begin
--构造sql查询条件(中间部分)
set @sqlCenter = @sqlCenter+'SELECT '+@primaryKeyName+' FROM '+@talbeName+' WHERE '+@contentFieldName+' like ''%'+dbo.Get_StrArrayStrOfIndex(@words,@splitString,@next)+'%'' UNION ALL '
set @next=@next+1
end
--处理sql语句中间部分,去除最后无用语句
set @sqlCenter=left(@sqlCenter,(len(@sqlCenter)-10))
--构造sql语句开头部分
set @sqlFirst='SELECT TOP '+@selectNumber+' '+@primaryKeyName+',COUNT(*) AS showCout FROM ('
--构造sql语句结尾部分
set @sqlLast=') AS t_Temp GROUP BY '+@primaryKeyName+' ORDER BY showCout DESC'
--拼接出完整sql语句,并执行
execute(@sqlFirst+@sqlCenter+@sqlLast)
END

调用示例:

  1. executeproc_Common_SuperLike 'id','t_test','content','20','|','i|o|c'

id表的主键字段名称。

t_test表名。

content匹配内容字段名称。

20选出20个记录(从顶至下匹配度越来越低)。

|关键字的分隔符号。

i|o|c一共有i,o,c三个关键字,通过|分隔。

SQL LIKE语句多条件贪婪匹配算法的更多相关文章

  1. SQL 视图 局部变量 全局变量 条件语句 事务 触发器

    一.视图 1.视图是一张虚拟表,他所存储的不是实际数据,而是查询语句,但我们可以对视图进行像数据表一样的操作. 2.为什么使用视图呢?我的理解是:1.在远程传输数据时,可以避免过长的查询字符,减少流量 ...

  2. sql语句之条件,分页,排序

    sql语句之条件,分页,排序

  3. SQL查询语句分类

    SQL查询语句有多种,下面总结下.首先先建三张表用于后面的实验 -- 学生表,记录学生信息 CREATE TABLE student( sno ), sname ), ssex ENUM('男','女 ...

  4. [转]MySQL 最基本的SQL语法/语句

    MySQL 最基本的SQL语法/语句,使用mysql的朋友可以参考下.   DDL-数据定义语言(Create,Alter,Drop,DECLARE) DML-数据操纵语言(Select,Delete ...

  5. SQL入门语句之ORDER BY 和GROUP BY

    一.SQL入门语句之ORDER BY ORDER BY 是用来基于一个或多个列按升序或降序顺序排列数据 1.从数据库表获取全部数据按字段A的升序排列 select *from table_name o ...

  6. SQL入门语句之LIKE、GLOB和LIMIT

    一.SQL入门语句之LIKE LIKE用来匹配通配符指定模式的文本值.如果搜索表达式与模式表达式匹配,LIKE 运算符将返回真(true),也就是 1.这里有两个通配符与 LIKE 运算符一起使用,百 ...

  7. SQL入门语句之SELECT和WHERE

    一.SQL入门语句之SELECT SELECT语句用于从数据库表中获取数据,结果表的形式返回数据.这些结果表也被称为结果集 1.从数据库表中取部分字段 select 字段A,字段B from tabl ...

  8. SQL入门语句之INSERT、UPDATE和DELETE

    一.SQL入门语句之INSERT insert语句的功能是向数据库的某个表中插入一个新的数据行 1.根据对应的字段插入相对应的值 insert into table_name(字段A, 字段B, 字段 ...

  9. SQL SELECT 语句

      本章讲解 SELECT 和 SELECT * 语句. SQL SELECT 语句 SELECT 语句用于从表中选取数据. 结果被存储在一个结果表中(称为结果集). SQL SELECT 语法 SE ...

随机推荐

  1. 有趣的win8进度条

    有趣的win8进度条 刚才在安装visual studio 12,发现它的安装界面都是win8风格的,而且安装的时候有个进度条,看着挺不错,就用 jquery 实现了一下,的确挺有趣: 点击停止效果 ...

  2. 【Win32API】SendInput ERROR_BUSY 错误原因

    最近需要解决一个Windows上模拟键盘输入的问题, 使用SendInput这个API来实现的.当我从另外一台机器给当前机器发送一条键盘指令时,发现SendInput一直是成功的,但是没有看到任何输入 ...

  3. linux下安装NPM管理工具

    根据”挖一下“开发需要,选择nodejs实现异步IO,目的是为了解决服务器卡死导致无法处理后续的http请求.看了花瓣的架构视频讲座,才决定这么做的,挺有道理的. 安装nodejs很顺利,下载源码包, ...

  4. UITableView的常用方法与示例

    实例方法 dequeueReusableCellWithIdentifier: 初始化一个指定重用标识符的UITableCell对象 两个协议 UITableViewDataSource tableV ...

  5. Jenkins+PMD构建自动化静态代码检测

    前言:软件缺陷是不可避免的,要尽量减少错误并提高软件质量,主要有两在类技术,即缺陷预防和缺陷检测 缺陷预防包括编写更好的设计规范.实施代码审核制度.运行代码静态分析工具.运行单元测试等 PMD是一种开 ...

  6. 12157 - Tariff Plan

      Ampang Communications & Mobile (ACM) provides telecom services for various types of users. Sin ...

  7. 从ICassFactory为CLSID为{17BCA6E8-A950-497E-B2F9-AF6AA475916F}的COM组件创建实例失败,原因是出现以下错误:c001f011.(Microsoft.Server.manageDTS

    从ICassFactory为CLSID为{17BCA6E8-A950-497E-B2F9-AF6AA475916F}的COM组件创建实例失败,原因是出现以下错误:c001f011.(Microsoft ...

  8. gRPC helloworld service, RESTful JSON API gateway and swagger UI

    概述 本篇博文完整讲述了如果通过 protocol buffers 定义并启动一个 gRPC 服务,然后在 gRPC 服务上提供一个 RESTful JSON API 的反向代理 gateway,最后 ...

  9. C语言之循环结构 for(一)

    一 for循环的介绍 语法: for(表达式1;表达式2;表达式3){ 循环体; } 循环步骤: A.执行表达式1,执行完毕跳转到B B.判断表达式2的结果是否为真,如果为真,跳转到C,否则跳转到E ...

  10. ASP.NET Zero--6.菜单加权限

    1.打开文件MpaNavigationProvider.cs [..\MyCompanyName.AbpZeroTemplate.Web\Areas\Mpa\Startup\MpaNavigation ...