0

個人とその詳細の一部を含む大規模なデータセットがあります。データセットには多数の重複が含まれており、多数のレコードがそれらの特徴の 1 つに基づいて相互に「関連」しています。正しいレコードがリンクされていることを確認するために、3 つのフィーチャのうち 2 つの一致がリンクとしてカウントされます。各個人は、可能なすべてのレコードにリンクする必要があり、それぞれに clusterId が割り当てられます。

次のデータセット構造があります。

+--+----+----+----+
|id|col1|col2|col3|
+--+----+----+----+
|1 |A   |B   |C   |
+--+----+----+----+
|2 |A   |B   |D   |
+--+----+----+----+
|3 |A   |Z   |D   |
+--+----+----+----+

ID 1 は ID 2 にリンクされ (col1 と col2 が同じであるため)、ID 2 は ID 3 にリンクされます (col1 と col3 が同じであるため)。ID 1 と 2 をリンクすると、この「クラスター」にさらに情報が追加され、リンクが確立された後、ID 3 はそのクラスターに属します。

データ セットは非常に大きく (2,800 万レコード)、適切な時間枠内でこれらの関係を構築できるかどうかはわかりません。

これを解決する最も速くてエレガントな方法は何ですか?

4

1 に答える 1

0

データが多すぎると、関係の作成に時間がかかる可能性がありますが、列にインデックスが付けられ、サーバーが高速である場合は、それほど悪くない可能性があります。関係を格納するテーブルを作成します。このSQLは関係を設定する必要があります。

CREATE TABLE RelationshipTable
    ([id1] int, [id2] int,[cluster] int);   

INSERT INTO RelationshipTable
    SELECT a.id,b.id,NULL
    FROM TestTable a
    LEFT JOIN TestTable b ON a.id<>b.id AND (
        (
                    ((a.col1 is null and b.col1 is null) or a.col1=b.col1)
                and ((a.col2 is null and b.col2 is null) or a.col2=b.col2)
        )
        OR
        (
                    ((a.col1 is null and b.col1 is null) or a.col1=b.col1)
                and ((a.col3 is null and b.col3 is null) or a.col3=b.col3)
        )
        OR
        (
                    ((a.col2 is null and b.col2 is null) or a.col2=b.col2)
                and ((a.col3 is null and b.col3 is null) or a.col3=b.col3)
        )
    )

DECLARE @UpdateId INT
DECLARE @ClusterId INT
SET @ClusterId=0

WHILE EXISTS(
    SELECT *
    FROM RelationshipTable
    WHERE [cluster] IS NULL
)
BEGIN
  SET @ClusterId=@ClusterId+1

  SELECT
    @UpdateId=[id1]
  FROM RelationshipTable
  WHERE [cluster] IS NULL

  UPDATE RelationshipTable
  SET [cluster]=@ClusterId
  WHERE ID1=@UpdateId
  OR ID2=@UpdateId

  WHILE @@Rowcount>0
  BEGIN
    UPDATE RelationshipTable
    SET [cluster]=@ClusterId
    WHERE [cluster] IS NULL
    AND
    (
      ID1 IN (
           SELECT ID1
           FROM RelationshipTable
           WHERE [cluster]=@ClusterId
           UNION
           SELECT ID2
           FROM RelationshipTable
           WHERE [cluster]=@ClusterId
      )
      OR ID2 IN (
           SELECT ID1
           FROM RelationshipTable
           WHERE [cluster]=@ClusterId
           UNION
           SELECT ID2
           FROM RelationshipTable
           WHERE [cluster]=@ClusterId
      )
    )
  END
END

select * from RelationshipTable
于 2013-02-05T13:27:19.870 に答える