none
全文检索,CONTAINS 和FREETEXT的用法比较 RRS feed

  • 问题

  • 在使用全文检索的时候,经常会用到CONTAINS 和FREETEXT,那么这两种方法有什么区别呢?
    2011年6月27日 9:34
    版主

答案

  • 他们都是在 WHERE 子句中使用的一个谓词,用于搜索含有基于字符的数据类型的列,以查找含义与搜索条件中的单词相同但不完全匹配的值。首先,CONTAINS可用于检索单个词或短语的精确或模糊匹配。FREETEXT则全文查询引擎将在内部对 输入的单词、短语或句子执行一些操作,并为每个字词分配权重,再查找匹配项。使用FREETEXT方法需要的开销比较大,也没有CONTAINS 的全文查询精度高。通过下面的实例,来演示这两种方法的差异。

    在这个例子中,将用到PUBS数据库(如果没有,可以从这里下载:http://www.microsoft.com/downloads/en/details.aspx?FamilyID=06616212-0356-46A0-8DA2-EEBC53A68034&displaylang=en)。

    use pubs;
    go 
    
    --为数据库启用全文检索
    exec sp_fulltext_database 'enable'
    --创建全文检索目录
    exec sp_fulltext_catalog 'PubsCatalog', 'create'
    --为表titles创建全文检索索引
    exec sp_fulltext_table 'titles', 'create', 'PubsCatalog', 'UPKCL_titleidind'
    --将要检索的字段添加到全文检索中
    exec sp_fulltext_column 'titles', 'title', 'add'
    exec sp_fulltext_column 'titles', 'notes', 'add'
    --启动全文索引的增量填充
    exec sp_fulltext_table 'titles', 'start_change_tracking'
    
    
    
    --CONTAINS
    SELECT title_id, title FROM Titles WHERE CONTAINS(notes, 'recipe')
    
    --执行结果
    title_id notes
    -------- --------
    PC1035 recipe
    
    (1 row(s) affected)
    
    
    --FREETEXT
    SELECT title_id, title FROM Titles WHERE FREETEXT(notes, 'recipe')
    
    --执行结果
    title_id notes
    -------- -------
    MC2222 Favorite recipes for quick, easy, and elegant meals.
    PC1035 recipe
    TC4203 More anecdotes fromthe Queen's favorite cook describing life among English royalty. Recipes, techniques, tender vignettes.
    
    (3 row(s) affected)
    
    

    从以上的执行结果, 使用CONTAINS方法是将字段中包含完全匹配“recipe”短语的记录检索出来。而FREETEXT方法是将字段中包含以“recipe”开始的短语的记录检索出来。

    2011年6月27日 9:35
    版主
  • CONTAINS方法中使用FORMSOF也可以像FREETEXT一样,对单个词或短语进行模糊匹配。如:
    SELECT title_id, notes FROM Titles WHERE CONTAINS(notes, 'FORMSOF(INFLECTIONAL, recipe)')
    
    --执行结果
    title_id notes
    -------- -------------------
    MC2222 Favorite recipes for quick, easy, and elegant meals.
    PC1035 recipe
    TC4203 More anecdotes from the Queen's favorite cook describing life among English royalty. Recipes, techniques, tender vignettes.
    
    (3 row(s) affected)
    
    

    通过CONTAINS跟FORMSOF结合,还可以检索多个词或短语,如:

    SELECT title_id, notes FROM Titles WHERE CONTAINS(notes, 'FORMSOF(INFLECTIONAL, recipe) or FORMSOF(INFLECTIONAL, cuisine)')
    
    --执行结果
    title_id notes
    -------- -------------
    MC2222 Favorite recipes for quick, easy, and elegant meals.
    PC1035 recipe
    TC3218 Profusely illustrated in color, this makes a wonderful gift book for a cuisine-oriented friend.
    TC4203 More anecdotes from the Queen's favorite cook describing life among English royalty. Recipes, techniques, tender vignettes.
    
    (4 row(s) affected)
    
    

    下面通过FREETEXT检索包含多个相关单词:

    SELECT title_id, notes FROM Titles WHERE FREETEXT (notes, 'cuisine recipe');
    
    --执行结果
    title_id notes
    -------- -------------
    MC2222 Favorite recipes for quick, easy,and elegant meals.
    PC1035 recipe
    TC3218 Profusely illustrated in color, this makes a wonderful gift book for a cuisine-oriented friend.
    TC4203 More anecdotes from the Queen's favorite cook describing life among English royalty. Recipes, techniques, tender vignettes.
    
    (4 row(s) affected)
    
    
    
    与CONTAINS不用,关键字“AND”在FREETEXT被认为是干扰词,直接忽略掉。同时,不允许使用 WEIGHT、FORMSOF、通配符、NEAR 和其他语法。系统将通过同义词库对 freetext_string 字符串进行断字处理、词干分析,然后执行同义词库查询。如果使用双引号将 freetext_string 引起来,将执行短语匹配;而不执行词干分析和同义词库查询处理。具体,请参阅:http://msdn.microsoft.com/zh-cn/library/ms176078.aspx



    2011年6月27日 9:37
    版主

全部回复

  • 他们都是在 WHERE 子句中使用的一个谓词,用于搜索含有基于字符的数据类型的列,以查找含义与搜索条件中的单词相同但不完全匹配的值。首先,CONTAINS可用于检索单个词或短语的精确或模糊匹配。FREETEXT则全文查询引擎将在内部对 输入的单词、短语或句子执行一些操作,并为每个字词分配权重,再查找匹配项。使用FREETEXT方法需要的开销比较大,也没有CONTAINS 的全文查询精度高。通过下面的实例,来演示这两种方法的差异。

    在这个例子中,将用到PUBS数据库(如果没有,可以从这里下载:http://www.microsoft.com/downloads/en/details.aspx?FamilyID=06616212-0356-46A0-8DA2-EEBC53A68034&displaylang=en)。

    use pubs;
    go 
    
    --为数据库启用全文检索
    exec sp_fulltext_database 'enable'
    --创建全文检索目录
    exec sp_fulltext_catalog 'PubsCatalog', 'create'
    --为表titles创建全文检索索引
    exec sp_fulltext_table 'titles', 'create', 'PubsCatalog', 'UPKCL_titleidind'
    --将要检索的字段添加到全文检索中
    exec sp_fulltext_column 'titles', 'title', 'add'
    exec sp_fulltext_column 'titles', 'notes', 'add'
    --启动全文索引的增量填充
    exec sp_fulltext_table 'titles', 'start_change_tracking'
    
    
    
    --CONTAINS
    SELECT title_id, title FROM Titles WHERE CONTAINS(notes, 'recipe')
    
    --执行结果
    title_id notes
    -------- --------
    PC1035 recipe
    
    (1 row(s) affected)
    
    
    --FREETEXT
    SELECT title_id, title FROM Titles WHERE FREETEXT(notes, 'recipe')
    
    --执行结果
    title_id notes
    -------- -------
    MC2222 Favorite recipes for quick, easy, and elegant meals.
    PC1035 recipe
    TC4203 More anecdotes fromthe Queen's favorite cook describing life among English royalty. Recipes, techniques, tender vignettes.
    
    (3 row(s) affected)
    
    

    从以上的执行结果, 使用CONTAINS方法是将字段中包含完全匹配“recipe”短语的记录检索出来。而FREETEXT方法是将字段中包含以“recipe”开始的短语的记录检索出来。

    2011年6月27日 9:35
    版主
  • CONTAINS方法中使用FORMSOF也可以像FREETEXT一样,对单个词或短语进行模糊匹配。如:
    SELECT title_id, notes FROM Titles WHERE CONTAINS(notes, 'FORMSOF(INFLECTIONAL, recipe)')
    
    --执行结果
    title_id notes
    -------- -------------------
    MC2222 Favorite recipes for quick, easy, and elegant meals.
    PC1035 recipe
    TC4203 More anecdotes from the Queen's favorite cook describing life among English royalty. Recipes, techniques, tender vignettes.
    
    (3 row(s) affected)
    
    

    通过CONTAINS跟FORMSOF结合,还可以检索多个词或短语,如:

    SELECT title_id, notes FROM Titles WHERE CONTAINS(notes, 'FORMSOF(INFLECTIONAL, recipe) or FORMSOF(INFLECTIONAL, cuisine)')
    
    --执行结果
    title_id notes
    -------- -------------
    MC2222 Favorite recipes for quick, easy, and elegant meals.
    PC1035 recipe
    TC3218 Profusely illustrated in color, this makes a wonderful gift book for a cuisine-oriented friend.
    TC4203 More anecdotes from the Queen's favorite cook describing life among English royalty. Recipes, techniques, tender vignettes.
    
    (4 row(s) affected)
    
    

    下面通过FREETEXT检索包含多个相关单词:

    SELECT title_id, notes FROM Titles WHERE FREETEXT (notes, 'cuisine recipe');
    
    --执行结果
    title_id notes
    -------- -------------
    MC2222 Favorite recipes for quick, easy,and elegant meals.
    PC1035 recipe
    TC3218 Profusely illustrated in color, this makes a wonderful gift book for a cuisine-oriented friend.
    TC4203 More anecdotes from the Queen's favorite cook describing life among English royalty. Recipes, techniques, tender vignettes.
    
    (4 row(s) affected)
    
    
    
    与CONTAINS不用,关键字“AND”在FREETEXT被认为是干扰词,直接忽略掉。同时,不允许使用 WEIGHT、FORMSOF、通配符、NEAR 和其他语法。系统将通过同义词库对 freetext_string 字符串进行断字处理、词干分析,然后执行同义词库查询。如果使用双引号将 freetext_string 引起来,将执行短语匹配;而不执行词干分析和同义词库查询处理。具体,请参阅:http://msdn.microsoft.com/zh-cn/library/ms176078.aspx



    2011年6月27日 9:37
    版主
  • 你好!

    我现在正在学习全文索引,过程中遇到一些问题:

    1、有的文章中介绍在生成全文索引的索引键时,对数据分词得到词元,然后词元又通过缩减和转变得到词根,最后使用词根生成了索引,那么contains为什么还是精确查找?比如:“Successful”最后的词根是“Success”,那么“Success”应该能够查到“Successful”的,但实际中不能查到,为什么?

    2、文章最后介绍:“如果使用双引号将 freetext_string 引起来,将执行短语匹配;而不执行词干分析和同义词库查询处理。”数据库对字符型只能使用但应哈(‘),你说的这种效果怎么实现的?怎么能够不执行处理完全匹配装个字符串?

    求解答,谢谢!!!

    2015年6月10日 7:57
  • Not sure where you found that article, is it from MS? Better to read related topics in sql books online.

    2015年6月10日 13:08
  • @rmiao 谢谢

    我想再请教一个问题:我使用SQL Server 2014数据库建表,表中包含字段FMARK,然后添加了全文索引在FMARK,表里有三条数据

    1、Favorite recipes for quick, easy, and elegant meals.

    2、recipe

    3、More anecdotes fromthe Queen's favorite cook describing life among English royalty. Recipes, techniques, tender vignettes.

    然后我使用CONTAINS和FREEETEXT进行搜索:

    SELECT * FROM COMPANY WHERE CONTAINS(FMARK,'recipe')

    SELECT * FROM COMPANY WHERE FREETEXT(FMARK,'recipe')

    两个查询结果一样,都只能查到第二条的数据。这里我有些疑惑:CONTAINS是精确匹配查找,那FREETEXT呢?他是分词之后也进行的精确匹配吗?如果这样的话,那使用FREETEXT除了直接输入字符串不用分词外,不仅占用资源多,而且还没有CONTAINS准确,那为什么要使用FREETEXT呢?FREETEXT有什么好处?

    如果您了解,麻烦您指导一下,或者推荐一下讲解这些知识的书籍。

    谢谢!!!

    2015年6月11日 2:17
  • Per books online:

    Freetext:

    • Separates the string into individual words based on word boundaries (word-breaking).
    • Generates inflectional forms of the words (stemming).
    • Identifies a list of expansions or replacements for the terms based on matches in the thesaurus. 

    Contains:

    • A word or phrase.
    • The prefix of a word or phrase.
    • A word near another word.
    • A word inflectionally generated from another (for example, the word drive is the inflectional stem of drives, drove, driving, and driven).
    • A word that is a synonym of another word using a thesaurus (for example, the word metal can have synonyms such as aluminum and steel).

    So have no difference when you search for single word.


    • 已编辑 rmiao 2015年6月11日 3:08
    2015年6月11日 3:07
  • 挖坟???

    Love SQL

    2015年6月11日 12:05
  • @rmiao 你好,你的回答解决了我的问题,谢谢!

    再麻烦你一下,问个问题:

    当创建了全文索引并使用的时候,是不是对数据库的同义词库进行填充和完整,这样保证使用FREETEXT分词和CONTAINS的模糊查询的时候,才能查询到更多结果?比如:我通过“recipe”要查到“recipes”,那么应该将“recipe”和“recipes”添加到同义词库中?

    Generates inflectional forms of the words (stemming) 这一步是怎么实现的?我在实践中,使用“recipe”查不到“recipes”

    2015年6月16日 6:50
  • @ForumFAQ 你好

    看了你的回答我有点疑惑,按照你的方法,我在SQL Server 2014中添加了数据并建立全文索引,当使用 SELECT title_id, title FROM Titles WHERE FREETEXT(notes, 'recipe') 语句进行查询,结果也是只有一条,并没有查出包含“recipes”的记录,这是为什么?FREETEXT并不能实现这种“recipe”到“recipes”的模糊查询啊!

    使用全文索引是不是要补充数据库的同义词库?

    2015年6月16日 6:53
  • @ForumFAQ 你好

    看了你的回答,对全文索引的使用更熟悉了。

    但是我有一个疑点,关于你最后提到的观点:“如果使用双引号将 freetext_string 引起来,将执行短语匹配;而不执行词干分析和同义词库查询处理。”,我尝试使用

    select * from COMPANY where freetext(FMARK,'眼镜框')
    select * from COMPANY where freetext(FMARK,'"眼镜框"')

    这两句查询的结果是一样的,加了双引号的第二句查询语句还是进行了分词,“眼镜框”分成了“眼”“镜框”。

    你这个观点应该是怎么操作的?

    2015年6月16日 7:01