2

私はこの結合テーブルを持っています:

 CREATE TABLE [TagMap](
[intItemId] [bigint] NOT NULL,
[intTagId] [bigint] NOT NULL,
 CONSTRAINT [PK_TagMap_intItemId] PRIMARY KEY CLUSTERED 
 (
[intItemId] ASC,
[intTagId] ASC
 ))

私の sproc は、次のように、seedItemId に関連付けられているタグを検出し、それらのタグに関連付けられている他の intItemIds を選択します。

 declare @baseTags table    (intTagId bigint primary key clustered);

INSERT INTO @baseTags (intTagId)
SELECT TOP 20 t1.intTagId
FROM   TagMap t1
WHERE t1.intItemId = 776

 SELECT TOP 500 t1.intItemId
 FROM   TagMap t1
      JOIN @baseTags t2
       ON t1.intTagId = t2.intTagId
 GROUP  BY t1.intItemId
 ORDER  BY Count(*) DESC

私がする必要があるのは、値が返されない 2 つの intItemIds の間のタグ関連付けの最小数 (たとえば 10) を指定することです。言い換えると、TagMap テーブルで、2 つの intItemId が共通に持つ 10 個以上の intTagId を見つけることができます。これは適切であり、それを選択します。それ以外の場合は無視します。

したがって、たとえば次のデータが与えられた場合:

 CREATE TABLE #TagMap(
 [intItemId] [bigint] NOT NULL,
 [intTagId] [bigint] NOT NULL,
 CONSTRAINT [PK_TagMap_intItemId] PRIMARY KEY CLUSTERED 
 (
 [intItemId] ASC,
 [intTagId] ASC
 ))

 insert into #TagMap
 (intItemId, intTagId)
 values 
 (1, 100),(1, 200),(1, 300),
 (2, 100),(2, 200),         (2, 500),(2, 600),
 (3, 100),                  (3, 500),(3, 600)

一致しきい値が 2 であるとします。

シードが intItemId 1 の場合、intItemId 2 のみが返されます (一致する 2 つのタグ ID: 100 と 200 があり、intItemId 3 には 1 つ: 100 があり、しきい値を下回っています)。

シードが intItemId 2 の場合、intItemId 1 と 3 の両方が返されます (intItemId 1 はタグ ID 100 と 200 に一致し、intItemId 3 はタグ ID 500 と 600 に一致します)。

シードが intItemId 3 の場合、intItemId 2 のみが返されます (一致する 2 つのタグ ID: 500 と 600 があり、intItemId には 1 つ: 100 があり、しきい値を下回っています)。

これを行う方法はありますか?

乾杯、マット

4

2 に答える 2

2
SELECT
  [foreign].intItemID
FROM
  #TagMap    AS [primary]
INNER JOIN
  #TagMap    AS [foreign]
    ON [foreign].intTagID = [primary].intTagID
WHERE
  [primary].intItemID = 1
GROUP BY
  [foreign].intItemID
HAVING
  COUNT(distinct [foreign].intTagID) >= @threshold

ただし、これはスケールがかなり悪いことに注意してください。「これらのタグのいずれかを持っているJOIN」を検索し、句でのみ「これらのタグをすべて持っている」を指定できるためです。HAVING

私の経験から、マイナーな最適化を行うことができますが、私が見つけた最もやりがいのあるアプローチは、結果をより標準的なマッピング テーブルにキャッシュすることでした。必要に応じて更新します。(タグ データの内容が変更されることはほとんどありません。)

于 2012-04-13T13:31:04.637 に答える
1

これはそれを行うようです(1、2、3に変化@InterestItemし、あなたが求めた結果を生成するようです):

declare @InterestItem int
set @InterestItem = 1
declare @Threshold int
set @Threshold = 2

select
    tm2.intItemId,
    COUNT(*)
from
    #TagMap tm1
        inner join
    #TagMap tm2
        on
            tm1.intTagId = tm2.intTagId and
            tm2.intItemId <> tm1.intItemId
where
    tm1.intItemId = @InterestItem
group by
    tm2.intItemId
having
    COUNT(*) >= @Threshold

現在、結果セットに を含めてCOUNTいますが、これを機能させるためには必要ありません。

于 2012-04-13T13:37:33.977 に答える