簡體   English   中英

如何在多個全文索引的任何列中搜索所有單詞?

[英]How do I search for ALL words within ANY columns of multiple Full Text indexes?

如果我在諸如ContactsCompanies表上有兩個全文索引,我如何編寫查詢以確保搜索短語的所有單詞都存在於兩個索引中的任何一個中?

例如,如果我正在搜索聯系人記錄或公司中存在所有關鍵字的聯系人,我將如何編寫查詢?

我試過在聯系人和公司表上都做CONTAINSTABLE ,然后將表連接在一起,但是如果我將搜索短語作為'"searchTerm1*' AND '"searchTerm2*"'傳遞給每個表,那么它只在所有搜索詞都在兩個索引上,返回的記錄太少。如果我像'"searchTerm1*' OR '"searchTerm2*"'那樣傳遞它,那么它匹配任何(而不是所有)搜索詞在一索引中的位置並返回太多記錄。

我還嘗試創建一個索引視圖,將聯系人與公司聯系起來,這樣我就可以一次性搜索所有列,但不幸的是,一個聯系人可能屬於多個公司,因此我將使用 ContactKey 作為視圖不再是唯一的,因此無法創建。

似乎我可能需要將短語分開並分別查詢每個單詞,然后將結果重新連接在一起以確保所有單詞都匹配,但我想不出如何編寫該查詢.

以下是模型外觀的示例:

Contact           CompanyContact    Company
--------------    --------------    ------------
ContactKey        ContactKey        CompanyKey
FirstName         CompanyKey        CompanyName
LastName

我在名字、姓氏上有一個全文索引,在 CompanyName 上有一個全文索引。

重建此答案是為了解決您的問題,因此字段中必須存在多個字符串。 請注意 CompanyContactLink 鏈接表中的單個鍵:

CREATE FULLTEXT CATALOG CompanyContact WITH ACCENT_SENSITIVITY = OFF
GO

CREATE TABLE Contact ( ContactKey INT IDENTITY, FirstName VARCHAR(20) NOT NULL, LastName VARCHAR(20) NOT NULL )
ALTER TABLE Contact ADD CONSTRAINT PK_Contact PRIMARY KEY NONCLUSTERED ( ContactKey )

CREATE TABLE Company ( CompanyKey INT IDENTITY, CompanyName VARCHAR(50) NOT NULL )
ALTER TABLE Company ADD CONSTRAINT PK_Company PRIMARY KEY NONCLUSTERED ( CompanyKey )
GO

CREATE TABLE CompanyContactLink ( CompanyContactKey INT IDENTITY NOT NULL, CompanyKey INT NOT NULL, ContactKey INT NOT NULL )
GO

INSERT INTO Contact ( FirstName, LastName ) VALUES ( 'Dipper', 'Pines' )
INSERT INTO Contact ( FirstName, LastName ) VALUES ( 'Mabel', 'Pines' )
INSERT INTO Contact ( FirstName, LastName ) VALUES ( 'Stanley', 'Pines' )
INSERT INTO Contact ( FirstName, LastName ) VALUES ( 'Soos', 'Ramirez' )
INSERT INTO Contact ( FirstName, LastName ) VALUES ( 'Wendy', 'Corduroy' )
INSERT INTO Contact ( FirstName, LastName ) VALUES ( 'Sheriff', 'Blubs' )
INSERT INTO Contact ( FirstName, LastName ) VALUES ( 'Bill', 'Cipher' )
INSERT INTO Contact ( FirstName, LastName ) VALUES ( 'Pine Dip', 'Nobody' )
INSERT INTO Contact ( FirstNAme, LastName ) VALUES ( 'Nobody', 'Pine Dip' )

INSERT INTO Company ( CompanyName ) VALUES ( 'Mystery Shack' )
INSERT INTO Company ( CompanyName ) VALUES ( 'Greesy Diner' )
INSERT INTO Company ( CompanyName ) VALUES ( 'Watertower' )
INSERT INTO Company ( CompanyName ) VALUES ( 'Manotaur Cave' )
INSERT INTO Company ( CompanyName ) VALUES ( 'Big Dipper Watering Hole' )
INSERT INTO Company ( CompanyName ) VALUES ( 'Lost Pines Dipping Pool' )
GO

INSERT INTO CompanyContactLink Values (3, 5), (1, 1), (1, 2), (1, 3), (1, 4), (1,5), (5,1), (3,1), (4,1)
GO

CREATE FULLTEXT INDEX ON Contact (LastName, FirstName)
KEY INDEX PK_Contact
ON CompanyContact
WITH STOPLIST = SYSTEM

CREATE FULLTEXT INDEX ON Company (CompanyName)
KEY INDEX PK_Company
ON CompanyContact
WITH STOPLIST = SYSTEM
GO

CREATE VIEW CompanyContactView
WITH SCHEMABINDING
AS
  SELECT
    CompanyContactKey,
    CompanyName,
    FirstName,
    LastName
  FROM
    dbo.CompanyContactLink
    INNER JOIN dbo.Company ON Company.CompanyKey = CompanyContactLink.CompanyKey
    INNER JOIN dbo.Contact ON Contact.ContactKey = CompanyContactLink.ContactKey
GO

CREATE UNIQUE CLUSTERED INDEX idx_CompanyContactView ON CompanyContactView (CompanyContactKey);
GO

CREATE FULLTEXT INDEX ON CompanyContactView (CompanyName, LastName, FirstName)
KEY INDEX idx_CompanyContactView
ON CompanyContact
WITH STOPLIST = SYSTEM
GO

-- Wait a few moments for the FULLTEXT INDEXing to take place.
-- Check to see how the index is doing ... repeat the following line until you get a zero back.

DECLARE @ReadyStatus INT
SET @ReadyStatus = 1
WHILE (@ReadyStatus != 0)
BEGIN
  SELECT @ReadyStatus = FULLTEXTCATALOGPROPERTY('CompanyContact', 'PopulateStatus')
END

SELECT
  CompanyContactView.*
FROM
  CompanyContactView
WHERE
  FREETEXT((FirstName,LastName,CompanyName), 'Dipper') AND
  FREETEXT((FirstName,LastName,CompanyName), 'Shack')
GO

以你在水塔的溫蒂為例:

SELECT
  CompanyContactView.*
FROM
  CompanyContactView
WHERE
  FREETEXT((FirstName,LastName,CompanyName), 'Wendy') AND
  FREETEXT((FirstName,LastName,CompanyName), 'Watertower')
GO

我創建了一個適用於任意數量全文索引和列的方法。 使用這種方法,可以很容易地添加要搜索的其他方面。

  1. 將搜索短語拆分為臨時表中的行
  2. 加入此臨時表以在每個適用的全文索引上使用 CONTAINSTABLE 搜索每個搜索詞。
  3. 將結果聯合在一起並獲得找到的搜索詞的不同計數。
  4. 過濾掉指定的搜索詞數量與找到的搜索詞數量不匹配的結果。

例子:

DECLARE @SearchPhrase nvarchar(255) = 'John Doe'
DECLARE @Matches Table(
    MentionedKey int,
    CoreType char(1),
    Label nvarchar(1000),
    Ranking int
)

-- Split the search phrase into separate words.
DECLARE @SearchTerms TABLE (Term NVARCHAR(100), Position INT)
INSERT INTO @SearchTerms (Term, Position)
SELECT dbo.ScrubSearchTerm(Term)-- Removes invalid characters and convert the words into search tokens for Full Text searching such as '"word*"'.
FROM dbo.SplitSearchTerms(@SearchPhrase)

-- Count the search words.
DECLARE @numSearchTerms int = (SELECT COUNT(*) FROM @SearchTerms)

-- Find the matching contacts.
;WITH MatchingContacts AS
(
    SELECT
        [ContactKey] = sc.[KEY],
        [Ranking] = sc.[RANK],
        [Term] = st.Term
    FROM @SearchTerms st
    CROSS APPLY dbo.SearchContacts(st.Term) sc -- I wrap my CONTAINSTABLE query in a Sql Function for convenience
)
-- Find the matching companies
,MatchingContactCompanies AS
(
    SELECT
        c.ContactKey,
        Ranking = sc.[RANK],
        st.Term
    FROM @SearchTerms st
    CROSS APPLY dbo.SearchCompanies(st.Term) sc
    JOIN dbo.CompanyContact cc ON sc.CompanyKey = cc.CompanyKey
    JOIN dbo.Contact c ON c.ContactKey = cc.ContactKey
)
-- Find the matches where ALL search words were found.
,ContactsWithAllTerms AS
(
    SELECT
        c.ContactKey,
        Ranking = SUM(x.Ranking)
    FROM (
        SELECT ContactKey, Ranking, Term FROM MatchingContacts  UNION ALL
        SELECT ContactKey, Ranking, Term FROM MatchingContactCompanies
    ) x
    GROUP BY c.ContactKey
    HAVING COUNT(DISTINCT x.Term) = @numSearchTerms
)
SELECT
    *
FROM ContactsWithAllTerms c

更新根據評論,這是我的SearchContacts函數的示例。 它只是一個簡單的包裝函數,因為我在多個過程中使用它。

CREATE FUNCTION [dbo].[SearchContacts]
(
    @contactsKeyword nvarchar(4000)
)
RETURNS @returntable TABLE
(
    [KEY] int,
    [RANK] int
)
AS
BEGIN
    INSERT @returntable
    SELECT [KEY],[RANK] FROM CONTAINSTABLE(dbo.Contact, ([FullName],[LastName],[FirstName]), @contactsKeyword)
    RETURN
END
GO

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM