我有一个记录超过mysql百万的数据库表,常常需要进行模糊搜索,即所谓的like "%关键词%",但速度超慢,在网站应用中几乎是不可能的。
mysql不支持中文的全文搜索,看文章有说对中文支持不好,主要是介于中文的分词功能缺乏。于是想到了使用urlencode编码改善之。下面举例说明:
原始表article
id
caption
caption_indexcaption是文章标题,装utf-8的编码的汉字。
caption_index装载caption字段的urlencode编码并去掉编码中的“%”,每个汉字的编码之间用空格分开。这样就线段与英文习惯了。
比如原caption字段的一条记录为:
“我爱北京天安门”
在插入这个记录时,同时插入这句话的urlencode的编码到caption_index中,
编码是:%e6%88%91 %e7%88%b1 %e5%8c%97 %e4%ba%ac %e5%a4%a9 %e5%ae%89 %e9%97%a8
去掉%后为 e68891 e788b1 e58c97 e4baac e5a4a9 e5ae89 e997a8 
然后对caption_index建立全文索引,搜索时,搜索词也进行相应的编码。
搜索结果显示当然是caption,而全文索引对用户是透明的。
这样做的原因是
1 我们经常对文章标题进行搜索,标题不大,增加一个“索引字段”再对该字段进行索引存储开销不是很大
2 去掉%影响不是很大,因为标题多为汉字,汉字一般解析为3个字节,有规律的排列,一般不会引起歧义
跟科学的做法是对中文进行分词,但这样的软件开销会很大,而且分词不成功会出现错误,使有点记录进入搜索死角。
举例:
“先进性教育”
分词为“先进性 教育”这没有问题,如果分词分为 “先进 性教育”,那么你要搜索“先进性”,你可能打死都搜索不到。
这就像一个一句话:I LOVE YOU,你却要搜索VEYO,当然搜索不到。所以这种分词可能带来很大的风险。即中文分词产生的歧义。上述的方法,其实是单词成词。我有些不明白是,在英文全文搜索里面,可不可以搜索一个短句,比如搜索“LOVE YOU”,就凡是含“love you”短句的都可以搜索得到,当然两个字是在一起的,如果这样,我上面的单子成词的方法是凑效的。
比如我要搜索“天安门”,我就在caption_index中全文搜索 “e5a4a9 e5ae89 e997a8”,这与英文本质上是一致的。
请教精通全文搜索的,在英文中如何使用全文搜索实现“短句”的搜索。
 

解决方案 »

  1.   

    我找到答案了,是可以的,即加双引号。
    问题是这样做会影响速度吗?比起like语句呢,是不是回去了?逻辑全文搜索支持下面的操作符:+ 
    一个领头的加号表示,该词必须出现在每个返回的记录行中。- 
    一个领头的减号表示,该词必须不出现在每个返回的记录行中。缺省的 (当既没有加号也没有负号被指定时)词是随意的,但是包含它的记录行将被排列地更高一点。这个模仿没有 IN BOOLEAN MODE 修饰词的 MATCH() ... AGAINST() 的行为。< > 
    这两个操作符用于改变一个词的相似性值的基值。< 操作符减少基值,> 操作符则增加它。参看下面的示例。( ) 
    圆括号用于对子表达式中的词分组。~ 
    一个领头的否定号的作用象一个否定操作符,引起行相似性的词的基值为负的。它对标记一个噪声词很有用。一个包含这样的词的记录将被排列得低一点,但是不会被完全的排除,因为这样可以使用 - 操作符。* 
    一个星号是截断操作符。不想其它的操作符,它应该被追加到一个词后,不加在前面。" 
    短语,被包围在双引号"中,只匹配包含这个短语(字面上的,就好像被键入的)的记录行。 
    这里是一些示例:apple banana 
    找至少包含上面词中的一个的记录行 
    +apple +juice 
    ... 两个词均在被包含 
    +apple macintosh 
    ... 包含词 “apple”,但是如果同时包含 “macintosh”,它的排列将更高一些 
    +apple -macintosh 
    ... 包含 “apple” 但不包含 “macintosh” 
    +apple +(>pie <strudel) 
    ... 包含 “apple” 和 “pie”,或者包含的是 “apple” 和 “strudel” (以任何次序),但是 “apple pie” 排列得比 “apple strudel” 要高一点 
    apple* 
    ... 包含 “apple”,“apples”,“applesauce” 和 “applet” 
    "some words" 
    ... 可以包含 “some words of wisdom”,但不是 “some noise words” 
      

  2.   

    我就是不想用分词插件功能。分词插件容易产生歧义。
    我昨晚想了一个办法,即按上述原则进行单字为词的办法对需要查找的字段进行urlencode编码。
    具体搜索是结合like语句综合利用。
    即取关键词的其中两个字用于全文索引搜索,搜索出来部分再用like进行检索。
    举例说,要搜索“我爱天安门”,在全文索引中搜索“我爱”的urlencode编码e68891 e788b1(主帖中已经说明这种编码办法),这个查询作为子查询。具体例子如下
    select × from article where caption like "%我爱天安门%" and id in (select id from article where match (caption_index) against ("+e68891 +e788b1"))这里的查询结果理论上与 select × from article where caption like "%我爱天安门%"是一样的。
    但速度有天壤之别,
    select × from article where caption like "%我爱天安门%"语句需要遍历所有记录,不管你建立索引没有,都需要遍历,这对上百万的记录来说已经是很费劲的了。
    但后面的复合查询就大不一样的,这个查询由两个查询组成,一个查询是select id from article where match (caption_index) against ("+e68891 +e788b1"),是全文查询的例子,查询在记录中必须包含“我”和“爱”的记录,这两个词可以不在一起。但经过这样的筛选,除非是很常见的助词分词,一般都能筛选到1000分之一的记录,就是说当进行第二个查询(like)查询时,它的遍历范围已经在1000分之一的记录中遍历了,这样所需要的时间就大大减少了。
    两者加起来,时间也不会很长。
    我对数据库了解不是很多,特别是在查询优化上,最近遇到这样的技术,只得摸索。
      

  3.   

    楼主的 caption_index字段是varchar类型的吗? 
    内容就是下边这样字符的形式存进去的? 
    “e68891 e788b1 e58c97 e4baac e5a4a9 e5ae89 e997a8”