0

私は全文検索にかなり慣れていないので、複数の無関係なテーブルに対して「サイト検索」スタイルの全文検索を実行するための最良のアプローチを本当に知りたいです(4つのテーブルに対してこれを実行することを計画しています)。私はそのようなビューを使用することを考えていました:

CREATE VIEW [dbo].[Search] WITH SCHEMABINDING
    AS

        SELECT   p.ProductId AS ItemId
            ,'Product' AS ItemType
            ,p.Title AS ItemTitle
            ,p.LongDescription AS LongDescription
            ,p.Price AS Price
    FROM dbo.Product AS p
    WHERE p.IsActive = 1

    UNION

    SELECT   a.ArticleId AS ItemId
            ,'Article' AS ItemType
            ,a.ArticleTitle AS ItemTitle
            ,a.Contents AS LongDescription
            ,NULL AS Price
    FROM dbo.Article AS a
    WHERE a.IsActive = 1

しかし、インデックスの正しい構文を調査しているときに、「a」には一意のインデックスが必要であり、「b」は明らかにユニオンのビューを使用してフルテキストインデックスを作成できないことに気付きました。

私が見た別のアプローチは、テーブルごとにFTIを作成し、ストアドプロシージャで、それらをtmpテーブルにUNIONしてから、OrderByランクのtmpテーブルを選択することでした。

私はこれに関するいくつかのガイダンスに本当に感謝しています。ビューへの結合が問題を克服するのに十分である複数の関連するテーブルに関連して私が見つけたもののほとんど。

編集:

@Joeは、私が忘れて実際に解決したこの質問に親切に答えましたが、少し長かったのではないかと心配していました。彼が提案した2つの方法の中で最も論理的であるように思われます。これが、私が提案した方法です。 m使用中-私はそれをページングする必要があることを完全に忘れていました...クライアントが結果の無限のリストに興奮していたとは思わない...

私の同僚はまた、メタデータをテーブルにスローし、基本的に結果を別のテーブルにキャッシュしてから全文検索を実行するという、彼が実装した別の手法を提案しました。メタデータはプラスになります。また、実際の結果をすぐに取得するか、表示するために、元のテーブルにキーを設定する必要があります(いわば必要に応じて記事全体)

    CREATE PROCEDURE [dbo].[up_Search]
     @Term VARCHAR(100)
    ,@Skip INT = 0
    ,@Take INT = 10
AS
DECLARE @Search TABLE
(
     ItemId INT
    ,ItemType VARCHAR(50)
    ,ItemTitle VARCHAR(100)
    ,LongDescription VARCHAR(MAX)
    ,Price DECIMAL(10,2)
    ,SearchRank INT
)

INSERT INTO @Search SELECT * FROM (

    SELECT   p.ProductId AS ItemId
            ,'Product' AS ItemType
            ,p.Title AS ItemTitle
            ,p.LongDescription AS LongDescription
            ,p.Price AS Price
            ,KEY_TBL.RANK AS SearchRank
    FROM dbo.Product AS p
    INNER JOIN CONTAINSTABLE(dbo.Product, Title, @Term) AS KEY_TBL ON p.ProductId = KEY_TBL.[KEY]
    WHERE p.IsActive = 1

    UNION

    SELECT   a.ArticleId AS ItemId
            ,'Article' AS ItemType
            ,a.ArticleTitle AS ItemTitle
            ,a.Contents AS LongDescription
            ,NULL AS Price
            ,KEY_TBL.RANK AS SearchRank
    FROM dbo.Article AS a
    INNER JOIN CONTAINSTABLE(dbo.Article, ArticleTitle, @Term) AS KEY_TBL ON a.ArticleId = KEY_TBL.[KEY]
    WHERE a.IsActive = 1

    UNION    

    SELECT   n.NewsId AS ItemId
            ,'News' AS ItemType
            ,n.NewsTitle AS ItemTitle
            ,n.Contents AS LongDescription
            ,NULL AS Price
            ,KEY_TBL.RANK AS SearchRank
    FROM dbo.News AS n
    INNER JOIN CONTAINSTABLE(dbo.News, NewsTitle, @Term) AS KEY_TBL ON n.NewsId = KEY_TBL.[KEY]
    WHERE n.IsActive = 1

    UNION

    SELECT   b.BusinessId AS ItemId
            ,bt.Title AS ItemType
            ,b.Title AS ItemTitle
            ,b.LongDescription AS LongDescription
            ,NULL AS Price
            ,KEY_TBL.RANK AS SearchRank
    FROM dbo.Business AS b
    INNER JOIN CONTAINSTABLE(dbo.Business, Title, @Term) AS KEY_TBL ON b.BusinessId = KEY_TBL.[KEY]
    INNER JOIN dbo.BusinessType AS bt ON b.BusinessTypeId = bt.BusinessTypeId
    WHERE b.IsActive = 1
) AS tmp;

WITH SearchCT AS
(
    SELECT   ItemId
            ,ItemType
            ,ItemTitle
            ,LongDescription
            ,Price
            ,SearchRank
            ,ROW_NUMBER() OVER (ORDER BY SearchRank DESC) AS RowNumber
            ,COUNT(*) OVER () AS RecordCount
    FROM @Search
)
SELECT ItemId, ItemType, ItemTitle, LongDescription, SearchRank, RowNumber, RecordCount
FROM SearchCT
WHERE RowNumber BETWEEN @Skip + 1 AND (@Skip + @Take)
ORDER BY RowNumber

0を返す

4

1 に答える 1

2

ここで実行できる基本的なアプローチは2つあると思います。

1)4つのテーブルを1つのテーブルに集約し、そのテーブルを検索します。このテーブルの主キーには一意の識別子が必要です。したがって、テーブル構造は、検討しているインデックス付きビューに似ており、次のようになります。

CREATE TABLE AggregatedTable
(
    Id int IDENTITY(1,1) primary key,
    ItemId int,
    ItemType nvarchar(50),
    ItemTitle nvarchar(255),
    LongDescription nvarchar(max),
    IsActive int
)

次に、LongDescription列にフルテキストインデックスを作成する必要があります。

このアプローチの利点は、次のように、単一のクエリで単一のテーブルに対して全文検索を実行できることです。

SELECT Id, ItemId, ItemType, ct.RANK      
    FROM dbo.AggregateTable AS a INNER JOIN 
    CONTAINSTABLE (AggregateTable , *, '(light NEAR aluminum)',   1033) AS ct
        ON a.ItemId= ct.[KEY]
WHERE IsActive = 1
ORDER BY ct.RANK desc

このアプローチの欠点は次のとおりです。1。定期的にジョブを実行して、4つのベーステーブルから集約テーブルにデータをロードする必要があります。2。ディスク容量を2倍使用します。

2番目のアプローチは、データを4つの別々のテーブルに保持してから、4つのテーブルの結果をUNIONするFTSクエリを作成することです。結果を関連性でランク付けしてから、最も関連性の高い上位N件の結果を取得できるはずです。次のようにクエリを作成する必要があります。

SELECT   p.ProductId AS ItemId, 'Product' AS ItemType, ct.RANK 'Rank'       
    FROM dbo.Product AS p INNER JOIN 
    CONTAINSTABLE (Product, *, '(light NEAR aluminum)',   1033) AS ct
        ON p.ProductId = ct.[KEY]
WHERE p.IsActive = 1
UNION
SELECT   a.ArticleId AS ItemId, 'Article' AS ItemType, ct.RANK  
      CONTAINSTABLE (Article, *, '(light NEAR aluminum)',   1033) AS ct
        ON p.ProductId = ct.[KEY]  
    FROM dbo.Article AS a
    WHERE a.IsActive = 1
    ORDER BY 'Rank' DESC
UNION ... other two tables

このアプローチの利点は、4つのテーブルのコンテンツを1つのテーブルに集約するジョブを用意する必要がないことです。

欠点は、4つのクエリの結果をUNIONする必要があるため、クエリがより複雑になることです。

私は2番目のアプローチに傾倒します。これは、より簡単で保守が容易であり、UNIONクエリの作成も簡単だと思います。

于 2012-05-25T01:53:40.770 に答える