【问题标题】:Searchable text is in 2 tables, how to design full text index?可搜索的文本在 2 个表中,如何设计全文索引?
【发布时间】:2013-03-04 17:01:37
【问题描述】:
在论坛应用程序中,线程的实际名称存储在一个表中,然后回复存储在另一个表中。
Table_Thread
Subject varchar(255) e.g. "How to setup fulltext search"
Table_Replies (users replies here)
ReplyText text(not null)
现在我想在主题和回复列上创建一个全文搜索,但它们看起来非常相关,所以它们应该在同一个索引中。
可以这样做吗?
我使用的是 sql server 2005。
【问题讨论】:
标签:
sql-server
sql-server-2005
full-text-search
【解决方案1】:
假设主题和回复之间存在关联,您可以创建一个视图 WITH SCHEMABINDING,在该视图上创建一个 UNIQUE CLUSTERED 索引,然后将该视图添加到您的全文目录中,选择您想要包含的两列。
【解决方案2】:
当大量并发查询请求到来时,RDBMS 无法通过 SQL 承担。此外,select SQL 对全文搜索的支持很差。因此,您需要 IR(信息检索)库,例如用于 java 的 Lucene。
【解决方案3】:
您可以创建一个索引视图,其中包含两个索引列 + 表的 PK 的联合
例如
CREATE VIEW SearchText
WITH SCHEMABINDING
AS SELECT * FROM (
(Subject as Text, Table_Thread_ID as ID, 1 as Type FROM Table_Thread)
UNION ALL
(ReplyText as Text, Table_Replies_ID as ID, 2 as Type FROM Table_Replies));
我将类型 1 和 2 设置为任意类型,因为您需要一个唯一的键来构建全文索引。
然后在 (ID, Type) 上创建唯一索引,最后创建全文索引。
CREATE UNIQUE INDEX SearchText_UK ON SearchText (ID, Type);
CREATE FULLTEXT CATALOG ft AS DEFAULT;
CREATE FULLTEXT INDEX ON SearchText(Text)
KEY INDEX SearchText_UK
WITH STOPLIST = SYSTEM;
【解决方案4】:
我已经看到 NopCommerce(C# MVC 开源电子商务)在“产品”和“变体”上使用全文搜索所做的事情,并且只返回“产品”。这与您的情况非常相似,因为您想搜索“线程”和“回复”,但显然您只想返回“线程”。我已将其更改为使用线程和回复:
首先,创建一个按表生成索引名的函数(可选):
CREATE FUNCTION [dbo].[nop_getprimarykey_indexname]
(
@table_name nvarchar(1000) = null
)
RETURNS nvarchar(1000)
AS
BEGIN
DECLARE @index_name nvarchar(1000)
SELECT @index_name = i.name
FROM sys.tables AS tbl
INNER JOIN sys.indexes AS i ON (i.index_id > 0 and i.is_hypothetical = 0) AND (i.object_id=tbl.object_id)
WHERE (i.is_unique=1 and i.is_disabled=0) and (tbl.name=@table_name)
RETURN @index_name
END
GO
然后,通过创建目录和索引来启用全文:
EXEC('
IF NOT EXISTS (SELECT 1 FROM sys.fulltext_catalogs WHERE [name] = ''myFullTextCatalog'')
CREATE FULLTEXT CATALOG [myFullTextCatalog] AS DEFAULT')
DECLARE @create_index_text nvarchar(4000)
SET @create_index_text = '
IF NOT EXISTS (SELECT 1 FROM sys.fulltext_indexes WHERE object_id = object_id(''[Table_Thread]''))
CREATE FULLTEXT INDEX ON [Table_Thread]([Subject])
KEY INDEX [' + dbo.[nop_getprimarykey_indexname] ('Table_Thread') + '] ON [myFullTextCatalog] WITH CHANGE_TRACKING AUTO'
EXEC(@create_index_text)
SET @create_index_text = '
IF NOT EXISTS (SELECT 1 FROM sys.fulltext_indexes WHERE object_id = object_id(''[Table_Replies]''))
CREATE FULLTEXT INDEX ON [Table_Replies]([ReplyText])
KEY INDEX [' + dbo.[nop_getprimarykey_indexname] ('Table_Replies') + '] ON [myFullTextCatalog] WITH CHANGE_TRACKING AUTO'
EXEC(@create_index_text)
然后,在通过关键字获取产品的存储过程中,构建一个临时表,其中包含与关键字匹配的产品ID列表。
INSERT INTO #KeywordThreads ([ThreadId])
SELECT t.Id
FROM Table_Thread t with (NOLOCK)
WHERE CONTAINS(t.[Subject], @Keywords)
UNION
SELECT r.ThreadId
FROM Table_Replies r with (NOLOCK)
WHERE CONTAINS(pv.[ReplyText], @Keywords)
现在您可以使用临时表#KeywordThreads 加入线程列表并返回它们。
我希望这会有所帮助。