2010-07-21 3 views
0

나는 동일 단락을 찾으려면그룹화 부모는

Paragraph 
--------- 
ParagraphID PK 
// other attributes ... 


Sentence 
-------- 
SentenceID PK 
ParagraphID FK -> Paragraph.ParagraphID 
Text   nvarchar(4000) 
Offset  int 
Score  int 
// other attributes ... 

이 부모 - 자식 관계를 가지고; 그 문장의 동일한 집합을 포함하는 단락입니다. 문장, 오프셋 및 점수가 같으면 문장 두 개가 동일하게 간주됩니다. 문장의 ID/ParagraphID는 비교의 일부가 아니며 동일한 문장 집합을 포함하면 두 단락이 동일합니다.

다른 누군가가 동일한 단락을 찾는 쿼리를 어떻게 보여줄 수 있습니까?

편집 : ca. 150,000 단락 및 1.5M 문장 출력에는 ParagraphID와이 단계와 동일한 가장 낮은 단락 ID가 포함되어야합니다. 예 : 단락 1과 단락 2가 같으면 출력은

ParagraphID EquivParagraphID 
1   1 
2   1 

답변

1

즉, 각 단락마다 서명이 필요하고 서명을 비교해야합니다. 당신은 출력 그 자체의 성격을 언급하지 않았습니다. . 여기에, 나는 "각각 동일한 단락 서명을 쉼표로 구분 ParagraphId 값의 행을 반환하고있어

With ParagraphSigs As 
    (
    Select P.ParagraphId 
     , Hashbytes('SHA1' 
       , (
        Select '|' + S1.Text 
         '|' + Cast(S1.Offset As varchar(10)) 
         '|' + Cast(S1.Score As varchar(10)) 
        From Sentence As S1 
        Where S1.ParagraphId = P.ParagraphId 
        Order By S1.SentenceId 
        For Xml Path('') 
        )) As Signature 
    From Paragraph As P 
    ) 
Select Stuff(
      (
      Select ', ' + Cast(PS1.ParagraphId As varchar(10)) 
      From ParagraphSigs As PS1 
      Where PS1.Signature = PS.Signature 
      For Xml Path('') 
      ), 1, 2, '') As Paragraph 
From ParagraphSigs As PS 
Group By PS.Signature 

이 원하는 출력에 대한 사용자 추가를 감안할 때, 당신과 같이 쿼리를 변경할 수 있습니다

With ParagraphSigs As 
    (
    Select P.ParagraphId 
     , Hashbytes('SHA1' 
       , (
        Select '|' + S1.Text 
         '|' + Cast(S1.Offset As varchar(10)) 
         '|' + Cast(S1.Score As varchar(10)) 
        From Sentence As S1 
        Where S1.ParagraphId = P.ParagraphId 
        Order By S1.SentenceId 
        For Xml Path('') 
        )) As Signature 
    From Paragraph As P 
    ) 
Select P1.ParagraphId, P2.ParagraphId As EquivParagraphId 
From ParagraphSigs As P1 
    Left Join ParagraphSigs As P2 
     On P2.Signature = P1.Signature 
      And P2.ParagraphId <> P1.ParagraphId 

분명히 3 개 또는 4 개의 단락이 같은 서명을 공유 할 가능성이있을 수 있으므로 위의 결과가 일치 단락 (예 : (P1, P2), (P1, P3), (P2, P1), (P2, P3), (P3, P1), (P3, P2))

의견에 abo 효과적으로 문장을 효과적으로 검색 할 수 있습니다. 이 구문을 사용할 수 있다면 잘 모르겠어요 (

With ParagraphsNeedingSigs As 
    (
    Select P1.ParagraphId 
    From Paragraph As P1 
    Where Exists (
        Select 1 
        From Paragraph As P2 
        Where P2.ParagraphId <> P1.ParagraphId 
         And P2.Offset = P1.Offet 
         And P2.Score = P1.Score 
        ) 
    ) 
    , ParagraphSigs As 
    (
    Select P.ParagraphId 
     , Hashbytes('SHA1' 
       , (
        Select '|' + S1.Text 
         '|' + Cast(S1.Offset As varchar(10)) 
         '|' + Cast(S1.Score As varchar(10)) 
        From Sentence As S1 
        Where S1.ParagraphId = P.ParagraphId 
        Order By S1.SentenceId 
        For Xml Path('') 
        )) As Signature 
    From ParagraphsNeedingSigs As P 
    ) 
Select P.ParagraphId, P2.ParagraphId As EquivParagraphId 
From Paragraph As P 
    Left Join ParagraphSigs As P1 
     On P1.ParagraphId = P.ParagraphId 
    Left Join ParagraphSigs As P2 
     On P2.Signature = P1.Signature 
      And P2.ParagraphId <> P1.ParagraphId 
+0

감사합니다. 전에는 해시 함수를 보지 못했습니다. 그래서 눈을 뜨게되었습니다. 가짜 일치가 통계적으로 중요하지 않더라도 단락을 동일하게 만들기위한 힌트로 키를 사용하는 방법이 있습니까? 그렇지만 문장 비교를 사용하여 완전히 확신 할 수 있습니까? 원하는 출력에 대한 내 업데이트도 참조하십시오. – mdma

+0

@mdma - 내 게시물을 업데이트했습니다. 즉, 두 개의 int 열을 기반으로 잠재적 인 일치가없는 단락을 필터링하고 잠재적 인 일치 가능성이있는 단락을 계산할 수 있습니다. – Thomas

+0

내 최종 쿼리는 이와 매우 비슷합니다. 나는 이것을 INTERSECT와 결합하여 해쉬 충돌을 제거하고 문장 세트가 정말로 동등한 지 확인했다. 그러나 오버 헤드가 몇 초에서 여러 분으로 걸렸다. (나는 결코 완료하지 않았다.) 대신 해시를 고유 한 데이터가되도록 실제 데이터를 참조하십시오. – mdma

1

당신은 SQL 2008 나열했기 때문에 : 두 개의 다른 매개 변수를 가지고 있기 때문에, 먼저 두 INT 컬럼에 비교하여 수행하여 생성 된 서명의 수를 줄일 수있다 2005 년), EXCEPT 또는 INTERSECT 비교를 사용할 수 있습니다. 상관 관계가있는 하위 쿼리가 포함되므로 성능이 문제가 될 수 있습니다.

SELECT 
    * 
FROM 
    Paragraph P 
WHERE 
    (SELECT COUNT(*) FROM 
(
    SELECT 
     S1.[Text], 
     S1.Offset, 
     S1.Score 
    FROM 
     Paragraph P1 
    INNER JOIN Sentence S1 ON 
     S1.ParagraphID = P1.ParagraphID 
    WHERE 
     P1.ParagraphID = P.ParagraphID 
    INTERSECT 
    SELECT 
     S2.[Text], 
     S2.Offset, 
     S2.Score 
    FROM 
     Paragraph P2 
    INNER JOIN Sentence S2 ON 
     S2.ParagraphID = P2.ParagraphID 
    WHERE 
     P2.ParagraphID > P.ParagraphID 
) SQ 
) = (SELECT COUNT(*) FROM Sentence P3 WHERE P3.ParagraphID = P.ParagraphID) 
+0

고맙습니다. 쿼리 실행을 시도했지만 5 분 후에 중지되었습니다. 연주회를 개선 할 수있는 방법이 있습니까? 질문에 표 크기와 원하는 출력을 추가했습니다. – mdma