7

各行に整数値が含まれる 7 つの列を持つ mysql テーブルがあります。

ユーザーから値を受け取る単純なサイトがあり、ユーザーから送信された値がテーブル内の行と一致するか、類似しているかどうかを確認する必要があります。

したがって、ユーザーは1 2 3 4 5 6 7入力などとして書き込みます。

テーブル内の行のいずれかが順序なしでそれに似ているかどうかを確認する必要があります。など1 2 3 4 5 6 7 = 7 6 5 4 3 2 1など。テーブルには 40,000 行を超えるデータが含まれている場合があります。

また、それらが少なくとも56または7数字を共有しているかどうかも確認する必要があります。

これは、順列を使用してすべての可能な組み合わせを見つけることを意味します。しかし、そのような問題に対する最善のアプローチは何ですか?

  1. ユーザーからの入力を取得し、すべての順列を取得して、最初の行、2 番目の行などと照合し、見つかった場合は報告しますか? または、その逆を行い、テーブルから行を取得し、すべての順列を取得して、ユーザー入力と照合しますか?

  2. 非常に多くの順列を持つこのような大きなテーブルを通過するときのメモリと CPU 使用率はどうですか?

4

3 に答える 3

3

完全に正規化されたスキーマでは、これは単一のクエリです。

pk を持つテーブルを次のように仮定します。

create table T1 
( pk char (1), a1 int, a2 int, a3 int, a4 int, a5 int, a6 int, a7 int);

insert into T1 values 
('a',1,2,3,4,5,6,7),
('b',2,3,4,5,6,7,8),
('z',10,11,12,13,14,15,16);

この時点で、データを次のように正規化できます。

select
   pk, 
   case a
    when 1 then a1
    when 2 then a2
    when 3 then a3
    when 4 then a4
    when 5 then a5
    when 6 then a6
    when 7 then a7
   end
   as v
from T1   
cross join 
   (select 1 as a from dual union all
    select 2 as a from dual union all
    select 3 as a from dual union all
    select 4 as a from dual union all
    select 5 as a from dual union all
    select 6 as a from dual union all
    select 7 as a from dual ) T2

前のクエリでは、要件を次の 1 つの条件に簡単に一致させることができます。

select pk
from
(
select
   pk, 
   case a
    when 1 then a1
    when 2 then a2
    when 3 then a3
    when 4 then a4
    when 5 then a5
    when 6 then a6
    when 7 then a7
   end
   as v
from T1   
cross join 
   (select 1 as a from dual union all
    select 2 as a from dual union all
    select 3 as a from dual union all
    select 4 as a from dual union all
    select 5 as a from dual union all
    select 6 as a from dual union all
    select 7 as a from dual ) T2
) T
where
   T.v in ( 4,5,6,7,8,9,10)
group by pk
having                                           <-- The Having
   count( pk ) > 4

結果

| PK |
------
|  b |
于 2012-11-26T11:14:11.770 に答える
1

簡単な方法は、データベースに追加のフィールドを追加することです。これは、7 つのフィールドすべてを組み合わせた番号順に並べたバージョンです。

例えば。データベース内のデータが 2 4 7 6 5 1 3 の場合、組み合わせフィールドは 1234567 になります。

次に、比較するときに、ユーザーの回答を数値で並べ替え、データベースの組み合わせフィールドと比較します。

あなたがしていることに応じて、次のようにクエリを書くことができます

select * from table where combination like '12%' or combination like '123%' 

一致する数字の最小数が必要なことがわかっている場合は、クエリが軽くなります

彼らが書いたものとデータベースにあるものがどれほど似ているかを調べるため。levenshtein PHP 関数を使用できます: http://php.net/manual/en/function.levenshtein.php

$result = levenshtein($input,$combination);
于 2012-11-26T10:43:56.133 に答える
0

残念ながら、このような問題に対して効率的にクエリを作成することはできません。

WHERE次のような句を作成できます。

(`1` IN ARRAY(1,2,3,4,5,6,7) 
    AND `2` IN ARRAY(1,2,3,4,5,6,7)
    AND `3` IN ARRAY(1,2,3,4,5,6,7)
    AND `4` IN ARRAY(1,2,3,4,5,6,7)
    AND `5` IN ARRAY(1,2,3,4,5,6,7))
OR
(`1` IN ARRAY(1,2,3,4,5,6,7) 
    AND `2` IN ARRAY(1,2,3,4,5,6,7)
    AND `3` IN ARRAY(1,2,3,4,5,6,7)
    AND `4` IN ARRAY(1,2,3,4,5,6,7)
    AND `6` IN ARRAY(1,2,3,4,5,6,7))
-- Each combination

しかし、それはとんでもない条件だろう。一方、次の組み合わせを使用してみてください。

まず、列1に情報が含まれているかどうかを確認します。

IF( `1` IN ARRAY(1,2,3,4,5,6,7), 1, 0)

次に、これらすべてのデータを合計します。

SELECT (
    IF( `1` IN ARRAY(1,2,3,4,5,6,7), 1, 0) +
    IF( `2` IN ARRAY(1,2,3,4,5,6,7), 1, 0) +
    IF( `3` IN ARRAY(1,2,3,4,5,6,7), 1, 0) +
    IF( `4` IN ARRAY(1,2,3,4,5,6,7), 1, 0) +
    IF( `5` IN ARRAY(1,2,3,4,5,6,7), 1, 0) +
    IF( `6` IN ARRAY(1,2,3,4,5,6,7), 1, 0) +
    IF( `7` IN ARRAY(1,2,3,4,5,6,7), 1, 0)
) AS `matches_cnt`
FROM t1
HAVING `matches_cnt` >= 5

これはすべての行を反復し、条件は非常に複雑です (したがって、ベッドのパフォーマンス)。

値をバイナリ文字列に置き換えてみることもできます。次に例を示します。

1,2,7 = 01000011

次に、チェックされたレコードとデータベースの間のハミング距離を計算しますが、これは条件の複雑さを減らすだけですが、すべてのレコードが同じままになるように反復する必要があります。

以下を使用した mysql での実装:

最初の部分を次のように置き換えます。

SELECT (
    $MAX_NUMBER$ - BIT_COUNT( XOR( `binary_representation`, $DATA_FROM_USER$))
) AS `matches_cnt`
于 2012-11-26T10:46:07.920 に答える