使用 microsoft sql server 2000 的全文搜索功能构建 web 搜索应用程序 andrew b. cencinimicrosoft corporation 2002年12月 适用于: microsoft® sql™ server 2000摘要:学习如何充分利用 sql server 2000 的全文搜索功能。本文包含有关实现最大吞吐率和最佳性能的几点提示和技巧。 目录简介 全文搜索功能简介 配置全文搜索功能 全文查询 排位和优化 其他性能技巧 小结 附录 a:实现全文搜索功能的最佳选择 附录 b:使用最佳选择、结果分页和有效全文查询逻辑的示例应用程序 附录 c:资源 简介使用 microsoft® sql™ server 2000 的全文搜索功能,可以对在非结构化文本数据上生成的索引执行快速、灵活的查询。常用的全文搜索工具是网站的搜索引擎。为了帮助读者理解全文搜索功能的最佳使用方法,本文介绍了大量抽象概念;并对优化全文索引和查询以实现最大吞吐率和最佳性能,提供了几点提示和技巧。全文搜索功能简介全文搜索功能在 sql server 7.0 中引入。全文搜索的核心引擎建立在 microsoft search (mssearch) 技术上,microsoft exchange 和 microsoft sharepoint™ portal server 等产品中也采用了此项技术。sql server 7.0 全文搜索中公开的功能可提供基本的文本搜索功能,并使用早期版本的 mssearch;而 sql server 2000 的全文搜索实现则包含一组可靠的索引和查询功能,并在 sql server 7.0 的基础之上添加了几项增强功能。这些增强功能包括:通过 microsoft 群集服务完全支持群集操作,能够过滤和索引 image 列中存储的文档,提供改进的语言支持,以及在性能、可缩放性和可靠性方面进行了改进。mssearch 生成、维护和查询文件系统中(而不是 sql server 中)存储的全文索引。mssearch 进行全文索引时使用的逻辑和物理存储单元是目录。全文目录在每个数据库中包含一个或多个全文索引 - 可以为 sql server 中的每个表创建一个全文索引,且索引中可以包含该表中的一列或多列。每个表只能属于一个目录,且每个表只能创建一个索引。我们将简单介绍有关组织全文目录和索引的最佳方案 - 但首先,让我们来简单了解一下全文搜索的工作原理。配置全文搜索功能要为 sql server 中存储的文本数据创建全文索引,应该先完成以下几步准备工作。第一步是以全文方式启用包含要生成索引的文本数据的数据库(如果您尚未执行此操作)。注意:执行以下语句将丢弃并重新创建属于要启用全文搜索的数据库的所有全文目录。除非要重新创建全文目录,否则请确保在要启用的特定数据库中未创建任何全文目录。如果您是 sysadmin 角色的成员或此数据库的 db_owner,可以继续进行并发出以下语句:use northwind exec sp_fulltext_database 'enable'
接下来,您需要创建全文目录,以存储全文索引。正如前面所提到的,此目录中的数据存储在文件系统中(而不是 sql server 中),因此,在考虑全文目录的存储位置时应该仔细选择。除非指定其他位置,否则全文目录将存储在 ftdata 目录(位于 microsoft sql server/mssql 存储位置中)的子目录中。以下是在非默认位置创建全文目录的方法:exec sp_fulltext_catalog 'cat_desc', 'create', 'f:/ft'
对于包含大量数据,且这些数据可适应此架构(或许是主架构)更改的系统,其性能会得到显著的提高。但在何时应用多个过滤器或不应用过滤器方面却有着明显的限制。当然,还有其他的方法可以解决这些问题。通过以上示例,您会了解一种将某些搜索条件抽象到架构的方法 - 实际上是“欺骗”优化程序(更确切的说是“成为”优化程序),因为在 sql server 本身的全文查询中当前不存在本地优化。其他性能技巧人们在聊天时常常问我的另一个问题是如何才能分页显示全文查询结果。换句话说,如果我要发出“root beer”查询,一次在某一 web 页上显示 40 个结果,并且只希望返回该页面上的 40 个结果(例如,如果我在第三页,我希望仅返回第 81 至第 120 条结果)。对于分页显示结果,我曾见过多种方法,但没有一种方法能够做到百分之百有效。我所推荐的方法可以最大程度地减少全文查询执行的次数(实际上,对于要分页显示的每个结果集只需执行一次),并将 web 服务器用作一个简单的缓存。从更高的层面来讲,您只需在全文查询中检索一个完整的主键和排位值行集合(如果需要,可以在架构中使用最佳选择并提取常用过滤器),并将其存储在 web 服务器的内存中(这取决于您的应用程序和负载,想象将 <32 字节的典型主键大小与 <4 字节的排位大小相加 [等于 <36 字节],然后乘以通常返回的结果集 <1000 行,最后等于 <35k。假定一个在任何给定时间返回 <1000 个活动查询结果集中的一个活动缓存集,您将发现此活动缓存集在 web 服务器上占用的内存少于 35mb - 这还可以接受)。为了分页显示结果,该进程只遍历 web 服务器的内存中存储的数组,并对 sql server 发出 select 以便只显示需要显示的行和列。这又回到了全文查询仅返回主键和排位的概念中 - select(甚至许多这样的查询语句)比全文查询的速度快许多倍。使用 select 而不是与基表合并多个行,并结合多个其他策略,您可以保留 sql server 计算机上更多的 cpu 周期,并且更有效、更划算地利用 web 领域。另一种可以替代 web 服务器端缓存的方法是在 sql server 自身中缓存结果集,并定义多种用于浏览这些结果的方法。虽然本文着重说明 web 服务器 (asp) 级别的应用程序设计,但 sql server 的可编程功能还为生成高性能的 web 搜索应用程序提供了强大的框架。小结microsoft sql server 2000 的全文搜索功能为索引和查询数据库中存储的非结构化文本数据提供了可靠、快速而灵活的方法。如果要广泛地将这种快速、准确的搜索功能应用于各种应用程序,那么很有必要充分利用其速度和精确性,来实现全文搜索解决方案。通过分布计算负载并通过某些巧妙的方式对数据进行组织,可以省下钱来购买其他硬件和软件,以摆脱因不必要的缓慢查询带来的困扰。在开发优秀的搜索应用程序时,通常要考虑到许多因素和注意事项,希望本文提供的信息和示例对您学习使用 sql server 2000 生成出色的 web 搜索应用程序会有所帮助。附录 a:实现全文搜索功能的最佳选择改进全文查询性能和有效性的一种可行方法是实现“最佳选择”系统。此系统是一种很简单的方法,可确保某些与特定查询表达式匹配的行先于其他行返回。最佳选择没有复杂的预编程逻辑(例如,sharepoint portal server 就包含这样的逻辑),因此,通常是首选办法。在本示例中挑选出最佳选择,并将唯一的主键和一些关键字存储在单独的表中。freetexttable 查询对(非常小的)最佳选择表执行,并且从该查询中返回的任何结果都与对基表的 freetexttable 查询结果一同返回。在给定这些搜索条件下,最先返回的将是所有“最佳选择”行,随后是被 mssearch 视为关联程度最高的行(以递减顺序返回)。下面是一个非常简单的用于创建最佳选择系统的示例脚本。use mydb
create table documenttable(ftkey int not null, document ntext)create unique index dtftkey_idx on documenttable(ftkey)
'----------------------------------------------------------------'' 显示与最佳选择/搜索词匹配的简单主键/排位 ''----------------------------------------------------------------'private sub searchnpage()
dim p ' 循环通过行时的计数器 dim numrows ' 缓冲/结果集中的总行数
if (usecache <> "1") then ' 获取最佳选择/结果并将其缓存
dim queryarg ' 传入的查询词 if (request.form("searchterm") <> "") then queryarg = request.form("searchterm") elseif (request.querystring("searchterm") <> "") then queryarg = request.querystring("searchterm") else response.write("未提供搜索词" & vbcrlf) exit sub end if
' 理想情况下,应该在此清理查询词... ' 添加自定义的清理逻辑,以防止 ' 随意执行 sql
' 调用 cleanstring(queryarg)
' 建立与 sql 的连接 set cn = server.createobject("adodb.connection") cn.open connectionstring
' 如果未返回任何结果,则结束 if (rs.eof and isempty(bbdata)) then response.write("没有匹配的行" & vbcrlf) call connclose exit sub end if
' 否则,获取行 if not(rs.eof) then alldata = rs.getrows session("results") = alldata end if
call connclose
else ' 从缓存加载 (usecache=1)
alldata = session("results")
' 在此获取要使用的行范围 if (request.form("firstrow") <> "") then firstrow = request.form("firstrow") lastrow = firstrow+pagesize elseif (request.querystring("firstrow") <> "") then firstrow = request.querystring("firstrow") lastrow = firstrow+pagesize end if
end if ' usecache<>true
' 对于本应用程序,只是打印出所有最佳选择 ' (可能比页面大小大),然后分页显示普通结果 ' 此处假设:在使用缓存时,如果没有新的最佳选择,' 则使用以前显示的最佳选择 if not(isempty(bbdata)) then response.write("最佳选择:" & vbcrlf) for p = 0 to ubound(bbdata, 2)response.write(bbdata(0,p) & " " & bbdata(1,p) & vbcrlf) next response.write(vbcrlf) end if
' 返回搜索结果(可能只有最佳选择) if not(isempty(alldata)) then if ubound(alldata, 2) < lastrow then lastrow = ubound(alldata, 2) end if
response.write("搜索结果:" & vbcrlf)
for p = firstrow to lastrowresponse.write(alldata(0,p) & " " & alldata(1,p) & vbcrlf) next end if ' not(isempty(alldata))
end sub
'----------------------------------------------------------------'' 关闭并清除连接对象 ''----------------------------------------------------------------'private sub connclose rs.close set rs = nothing cn.close set cn = nothingend sub
<form action="<搜索 asp 页面>" method="post">搜索词:<input name="searchterm"><p><input type="submit" value="search"></form>
</body></html>
正如以上两个代码示例所示,创建可执行有效全文查询(用最佳选择完成)并缓存和分页显示结果的 web 应用程序,并不需要花费太多的工夫。只需使用最低的系统开销,即可添加用于提供其他数据、增强最佳选择的外观以及在搜索结果中导航的逻辑(此外,强烈建议您实现其他用于错误处理、安全设置和清理传入数据的严密逻辑)。通过上面的高级建议和示例,使用 sql server 2000 全文搜索设计和实现快速可缩放的 web 搜索应用程序就是轻而易举的事情了。
附录 c:资源full-text search deployment(英文)http://support.microsoft.com/default.aspx?scid=/support/sql/content/2000papers/fts_white%20paper.asp是那些初次接触全文搜索的用户的最佳参考。介绍了填充方法及硬件和软件需求,并为使用 sql server 2000 全文搜索提供了提示、技巧和其他文档。全文搜索公共新闻组 (microsoft.public.sqlserver.fulltext)查找有关全文搜索问题的答案以及有用提示和技巧的理想场所。全文搜索新闻组是 sql server 开发小组和博学的 microsoft mvp 成员经常光顾的场所。