八、组合查询和全文本搜索

1.UNION

如果我们要执行多个查询条件,比如检索price不高于5或者供应商是1001,1002的商品。我们可以使用where...or...语句:

select products.vend_id,prod_id,prod_price  
from products  
where prod_price<=5 
or products.vend_id in (1001,1002);

但是我们还可以使用union将两个select语句合并起来:

mysql> select products.vend_id,prod_id,prod_price  from products  where prod_price<=5
-> union
-> select products.vend_id,prod_id,prod_price  from products  where products.vend_id in (1001,1002);

这两个检索语句结果一样。

注意:

  • UNION 中的每个查询必须包含相同的列、表达式或聚集函数。
  • UNION自动取消包含重复的行。 上述例子中,第一条select返回4个结果,第二条返回5个,但是使用union之后返回8个而不是9个。因为其中有一条既是1002厂商生产的,又是价格不高于5的。

如果我们不想取消这些行,将union改为union all.

若要排序,只能在最后一条select后面跟上order by.它作用于全部语句。

2.全文本搜索

  • 并非所有引擎都支持全文本搜索。 两个最常使用的引擎为MyISAM和InnoDB,前者支持全文本搜索,而后者不支持。
  • 在索引之后,SELECT可与Match()和Against()一起使用以实际执行搜索。

也可以稍后指定,不在创建的时候指定。

注意在导入数据的时候不要指定fulltext,因为更新索引需要花费时间。

使用例子:

select note_text  from productnotes 
where Match(note_text) Against('rabbit');

就可以匹配出出现'rabbit'的文本行。使用LIKE照样可以:

select note_text from productnotes
where note_text like '%rabbit%';

我们使用全文本搜索的优点在于:like返回的记录顺序没有特别的用处(或者说是规律)。而使用全文本搜索,我们是按匹配词的等级返回的。

看下面一条检索语句,我们把等级用数值表示出来:

select note_text,match(note_text) against('rabbit') as rank from productnotes \G;

如图所示,rank值为0的就是不包含匹配词'rabbit'的记录。我们返回顺序是优先级从高到底的顺序。
等级值:

  • 等级由MySQL根据行中词的数目、唯一词的数目、整个索引中词的总数以及包含该词的行的数目计算出来。
  • 文本中词靠前的行的等级值比词靠后的行的等级值高。

3. 查询扩展

除了查找出现匹配词的行之外,我们可能还需要检索出与这个词有关的行,但匹配的词却没有出现在这行中。

如我们要检索与'anvils'匹配的行:

mysql> select note_text from productnotes
-> where match(note_text) against('anvils');

这样我们只返回一条数据,其中包含'anvils'.

使用扩展查询时候:

  • 首先,进行一个基本的全文本搜索,找出与搜索条件匹配的所有行。
  • 其次,MySQL检查这些匹配行并选择所有有用的词。
  • 再其次,MySQL再次进行全文本搜索,这次不仅使用原来的条件,而且还使用所有有用的词。

所以MySQL进行查询扩展的时候进行了两次的全文搜索。

至于是如何选择有用的词,则之后学习。

语法:

mysql> select note_text from productnotes
-> where match(note_text) against('anvils' with query expansion);

这次我们返回了7条记录:

原因如上图。

4. 布尔文本搜索

布尔文本搜索即使没有fulltext索引也可以使用。

布尔方式可以提供以下细节:

  • 要匹配的词。

  • 要排斥的词(如果某行包含这个词,则不返回该行,即使它包含其他指定的词也是如此)。

  • 排列提示(指定某些词比其他词更重要,更重要的词等级更高)。

  • 表达式分组。

    select note_text from productnotes
    -> where match(note_text) against('heavy' in boolean mode);
    此条布尔查询和全文本搜索一致。但我们要如果需要排斥一个词呢?

    mysql> select note_text from productnotes
    -> where match(note_text) against('heavy -rope*' in boolean mode);
    此条布尔查询就可以返回不以'rope'开头的含有'heavy'的记录。

实例:

5.全文本搜索使用说明。

  • 短词被忽略。 在索引全文本数据时,短词被忽略且从索引中排除。短词定义为那些具有3个或3个以下字符的词(如果需要,这个数目可以更改)。
  • 内建词被忽略。 MySQL带有一个内建的非用词(stopword)列表,这些词在索引全文本数据时总是被忽略。如果需要,可以覆盖这个列表。
  • 50%规则。 许多词出现的频率很高,搜索它们没有用处(返回太多的结果)。因此,MySQL规定了一条50%规则,如果一个词出现在50%以上的行中,则将它作为一个非用词忽略。50%规则不用于 IN BOOLEAN MODE。
  • 小于三行不返回。 如果表中的行数少于3行,则全文本搜索不返回结果(因为每个词或者不出现,或者至少出现在50%的行中)。
  • 忽略单引号。 忽略词中的单引号。例如, don't 索引为 dont 。
  • 需要词分隔符。 不具有词分隔符(包括日语和汉语)的语言不能恰当地返回全文本搜索结果。
  • 仅在 MyISAM 数据库引擎中支持全文本搜索。
posted @ 2019-02-10 20:12  _NewMan  阅读(248)  评论(0编辑  收藏  举报