SQL Server 全文搜索/全文索引

SQL Server 全文搜索/全文索引

ZKEASOFT July 10, 2020


概述

全文引擎使用全文索引中的信息来编译可快速搜索表中的特定词或词组的全文查询。全文索引将有关重要的词及其位置的信息存储在数据库表的一列或多列中。全文索引是一种特殊类型的基于标记的功能性索引,它是由 SQL Server 全文引擎生成和维护的。生成全文索引的过程不同于生成其他类型的索引。全文引擎并非基于特定行中存储的值来构造 B 树结构,而是基于要编制索引的文本中的各个标记来生成倒排、堆积且压缩的索引结构。

  • 全文索引是针对数据表,只能对表创建全文索引,不能对数据库创建全文索引。
  • 每个数据库可以不包含全文目录或包含多个全文目录,一个全文目录可以包含多个全文索引,但一个全文索引只能用于构成一个全文目录。
  • 一个数据表只能创建一个全文索引,一个全文索引可以包含多个字段。
  • 创建全文索引的表必须要有一个唯一的非空索引,并且这个唯一的非空的索引只能是一个字段,不能是组合字段。
  • 每个表只允许有一个全文索引。
  • 可以对以下类型的列创建全文索引:charvarcharncharnvarchartextntextimagexmlvarbinary 和 varbinary(max),从而可对这些列进行全文搜索。对数据类型为 varbinaryvarbinary(max)imagexml的列创建全文索引需要您指定类型列,类型列是用来存储每行中文档的文件扩展名(.doc、.pdf、xls 等)的表列。

注意:全文搜索是 SQL Server 数据库引擎的一个可选组件, 如果你在安装 SQL Server 时没有选择全文搜索,请再次运行 SQL Server 安装程序来添加它。

如果已安装了全文搜索组件,可在服务中查看对应的服务是否有运行:

可以使用以下查询语句来查看对应的数据库是否已开启全文搜索:

SELECT DATABASEPROPERTY('{DatabaseName}', 'isfulltextenabled');

如果返回结果是 0,可以使用以下脚本进行启用:

EXEC sp_fulltext_database 'enable'

全文搜索查询与 LIKE 谓词的对比

LIKE与全文搜索不同,LIKE仅对字符模式有效。另外,不能使用LIKE来查询格式化的二进制数据。此外,对大量非结构化的文本数据执行LIKE查询要比对相同数据执行同样的全文查询慢得多。对数百万行文本数据进行的LIKE查询可能需要几分钟的时间才能返回结果;而对于同样的数据,全文查询只需要几秒甚至更少的时间,具体取决于返回的行数。

创建全文目录

全文目录用来存储全文索引。可以直接使用以下脚本进行创建:

CREATE FULLTEXT CATALOG DefaultFullTextCatalog;

或者使用管理工具的图形化界面进行创建:

为数据库表创建全文索引

为数据库表创建全文索引的时候需要指定对应的语言。因为不同的语言的分词都有所差异,SQL Server将会使用对应语言的分词器处理表中的数据。SQL Server的全文搜索支持大约 50 种不同语言,可通过查询sys.fulltext_languages表来查看所有支持的语言。

下面我们对Shop表的ShopName和ShopAddress两个字段添加简体中文的全文索引:

CREATE FULLTEXT INDEX ON [dbo].[Shop]
(  
    [ShopName] LANGUAGE 2052,
	[ShopAddress] LANGUAGE 2052
)  
KEY INDEX [PK_Shop] ON DefaultFullTextCatalog
WITH CHANGE_TRACKING AUTO

同样也可以使用管理工具的图形化界面进行创建:

全文搜索谓词/函数

全文查询使用全文谓词(CONTAINSFREETEXT)以及全文函数(CONTAINSTABLEFREETEXTTABLE)。它们支持复杂的 Transact-SQL 语法,这种语法支持各种形式的查询词。

CONTAINS

CONTAINS用于在 SQL Server 中搜索单个词和短语的精确或模糊(不太精确的)匹配项、在一定差别范围内的相近词或加权匹配项。

例如,查询商铺名或者地址中有福田的商铺:

SELECT * FROM dbo.Shop WHERE CONTAINS((ShopName, ShopAddress),N'福田')

CONTAINSTABLE

在查询方式上与CONTAINS几乎一样。但CONTAINSTABLE返回的是符合查询条件的表,在 SQL 语句中我们可以把它当作一个普通的表来使用,并且使用CONTAINSTABLE的查询对每一行返回一个相关性排名值 (RANK) 和全文键 (KEY)。RANK用于表示相关性的匹配程度,它的值在0~1000之间,KEY就是主表的ID。

所以我们的查询的时候可以使用RANK进行排序,将相关性高的排在前面:

SELECT T0.ShopID,
       T0.ShopName,
       T0.ShopAddress,
       T1.RANK
FROM dbo.Shop T0
    INNER JOIN CONTAINSTABLE
               (Shop, ShopAddress, N'福田') T1
        ON T0.ShopID = T1.[KEY]
ORDER BY T1.RANK DESC;

FREETEXT/FREETEXTTABLE

FREETEXT/FREETEXTTABLE的用法与 CONTAINS/CONTAINSTABLE一致。不同的在于FREETEXT/FREETEXTTABLE会先把要查询的词句先进行分词然后再查询匹配。

例如可以直接查询:福田的邮局,查询时SQL Server会自动拆分。

SELECT T0.ShopID,
       T0.ShopName,
       T0.ShopAddress,
       T1.RANK
FROM dbo.Shop T0
    INNER JOIN FREETEXTTABLE
               (Shop, (ShopName, ShopAddress), N'福田的邮局') T1
        ON T0.ShopID = T1.[KEY]
ORDER BY T1.RANK DESC;

另外,可以通过查询sys.dm_fts_parser来查看分词结果:

SELECT * FROM sys.dm_fts_parser ('"福田的邮局"', 2052, 0, 0);

更多

以上只列举了SQL Server全文搜索的一些基本知识和简单的用法,更详细的内容可以查看微软的官方文档


微信公众号