2

ドキュメント用語マトリックスを mysql に保存し、次のようなクエリの結果を取得したいと考えています。

例: token_id '1' と token_id '2' (場合によっては 2 以上) が 10 ワードの範囲内にあるすべての行を取得します。

私のテーブル:

dt_matrix_token_id int(11) PK AUTO_INCREMENT,
token_id int(11),
storage_data_id int(11),
position int(11)

したがって、基本的に token_id はトークンを表し、position はトークンが元のテキストのどの位置にあったかを表します。

token_id で行を選択することは問題ではありません。問題は、クエリ内で両方の単語が特定の「半径/範囲」内にある必要があることをどのように記述するかです。

Select * FROM dt_matrix_token WHERE token_id IN(1,2) AND ???

??? これは私が立ち往生した場所です。見つかった値に対してクエリを実行する必要があることをどのように伝えることができますか? 結果に位置 = 12 の行が含まれている場合、他のすべての有効な行は位置 >= 2 & 位置 =< 22 である必要があります。

ところで: 半径内の地理的位置のクエリに似ているでしょうか?

編集:サンプルデータの実際の進捗状況は次のとおりです:http://sqlfiddle.com/#!2/52f48/2

クエリは正常に動作しますが、まだ完全ではないため、ドキュメント内で 2x トークン 1 が一致する場合も「有効な」結果であり、これはもちろん false です。指定されたすべてのトークンがある場合にのみ正しいです。ソリューションは 3 つ以上のトークンに拡張可能でなければなりません。

4

1 に答える 1

2

dt_matrix_tokenテーブルの 2 番目のインスタンスと結合されたdt_matrix_tokenテーブルからのクエリから始めます。ここで、両方のインスタンスには、関心のある値の範囲内のtoken_idがありますが、両方が同じ値を持つことはできません。

それらはまた、一致するstorage_data_idを持つ必要があり(つまり、同じドキュメント内にある)、2 番目のトークンの位置は最初のトークン以上である必要があります。

SELECT mt1.dt_matrix_token_id, mt1.storage_data_id,
  mt1.token_id AS token_id1, mt2.token_id AS token_id2,
  mt1.position AS position1, mt2.position AS position2
FROM dt_matrix_token AS mt1
JOIN dt_matrix_token AS mt2
WHERE mt1.token_id IN (1,2,3) 
  AND mt2.token_id IN (1,2,3)
  AND mt1.token_id <> mt2.token_id
  AND mt1.storage_data_id = mt2.storage_data_id
  AND mt2.position >= mt1.position 

これにより、関心のある一連のトークンのすべてのペアが得られます。

ここで、最初のテーブルのdt_matrix_token_idでグループ化し、2 番目のテーブルのtoken_idと組み合わせて、最初のテーブルのすべてのトークンに対して、2 番目のテーブルの各token_idの 1 つに結果のセットを絞り込みます。

そして、2 番目のテーブルの結果をグループ化すると、気になるのは最小の順位です。2 番目のトークンは常に最初のトークンの後に続くため、これにより最初のトークンに最も近い位置が得られます。

SELECT mt1.dt_matrix_token_id, mt1.storage_data_id,
  mt1.token_id AS token_id1, mt2.token_id AS token_id2,
  mt1.position AS position1, MIN(mt2.position) AS position2
FROM dt_matrix_token AS mt1
JOIN dt_matrix_token AS mt2
WHERE mt1.token_id IN (1,2,3) 
  AND mt2.token_id IN (1,2,3)
  AND mt2.token_id <> mt1.token_id
  AND mt2.storage_data_id = mt1.storage_data_id
  AND mt2.position >= mt1.position 
GROUP BY mt1.dt_matrix_token_id, mt2.token_id

これで、関心のあるトークンのすべてのインスタンスについて、同じドキュメント内でそれに続くトークンのいずれかに最も近い位置が得られます。

しかし、本当に必要なのは、最初のトークンからそれに続くトークンまでの最大距離です。したがって、再度dt_matrix_token_idでグループ化し、2 番目の位置の最大値 (つまり、各token_idの最小値の最大値) までの距離を計算する必要があります。

SELECT dt_matrix_token_id, storage_data_id,
  MAX(position2)-position1 AS distance
FROM (
  SELECT mt1.dt_matrix_token_id, mt1.storage_data_id,
    mt1.position AS position1, MIN(mt2.position) AS position2
  FROM dt_matrix_token AS mt1
  JOIN dt_matrix_token AS mt2
  WHERE mt1.token_id IN (1,2,3) 
    AND mt2.token_id IN (1,2,3)
    AND mt2.token_id <> mt1.token_id
    AND mt2.storage_data_id = mt1.storage_data_id
    AND mt2.position >= mt1.position 
  GROUP BY mt1.dt_matrix_token_id, mt2.token_id
) AS temp
GROUP BY dt_matrix_token_id

ただし、最初のテーブルのすべてのトークンの後に、関心のある他のすべてのトークンが続くわけではありません。COUNTしたがって、各グループの結果が、対象のトークンの数から 1 を引いた値 (最初のテーブルでは 1 トークン、2 番目のテーブルでは n-1 トークン) に等しいことを確認する必要があります。

HAVINGこれは句 --で行うことができますHAVING COUNT(*) = 3-1。その式の 3 は、検索するトークンの数を表します。

気になるトークンのすべてのインスタンスについて、(同じドキュメント内で) 気になる他のすべてのトークンが後に続く場合、それらすべてをカバーする最短距離が得られます。

しかし、各ドキュメントに対して複数の結果が存在する可能性が非常に高く、実際にはそれぞれのケースで最短のものだけを知る必要があります。そのため、storage_data_idでグループ化し、グループ内の最小距離を計算する必要があります。

SELECT storage_data_id, MIN(distance) AS distance
FROM (
  SELECT dt_matrix_token_id, storage_data_id,
    MAX(position2)-position1 AS distance
  FROM (
    SELECT mt1.dt_matrix_token_id, mt1.storage_data_id,
      mt1.position AS position1, MIN(mt2.position) AS position2
    FROM dt_matrix_token AS mt1
    JOIN dt_matrix_token AS mt2
    WHERE mt1.token_id IN (1,2,3) 
      AND mt2.token_id IN (1,2,3)
      AND mt2.token_id <> mt1.token_id
      AND mt2.storage_data_id = mt1.storage_data_id
      AND mt2.position >= mt1.position 
    GROUP BY mt1.dt_matrix_token_id, mt2.token_id
  ) AS temp
  GROUP BY dt_matrix_token_id
  HAVING COUNT(*) = 3-1
) AS temp
GROUP BY storage_data_id

これにより、関心のあるすべてのトークンを含む各ドキュメントと、それらすべてのトークンをカバーする最小距離が得られます。HAVING結果を特定の範囲の距離に制限するには、別の句を追加するだけです。

HAVING distance <= 20

次に、そのクエリからの結果の数から、指定した範囲内で関心のあるすべてのトークンを含むドキュメントの数がわかります。

于 2013-08-03T23:55:57.153 に答える