sql >> データベース >  >> RDS >> PostgreSQL

多次元キューブ上のPostgresqlk最近傍法(KNN)

    PostgreSQLは距離演算子<->をサポートしています 私が理解しているように、これはテキストの分析(pg_trgrmモジュールを使用)およびジオメトリ データ型。

    複数の次元でどのように使用できるかわかりません。おそらく、独自の距離関数を定義するか、データをテキストまたはジオメトリタイプの1つの列に変換する必要があります。たとえば、8列のテーブル(8次元の立方体)がある場合:

    c1 c2 c3 c4 c5 c6 c7 c8
     1  0  1  0  1  0  1  2
    

    次のように変換できます:

    c1 c2 c3 c4 c5 c6 c7 c8
     a  b  a  b  a  b  a  c
    

    次に、1つの列を持つテーブルに移動します:

    c1
    abababac
    

    次に、(gistを作成した後に)を使用できます インデックス ):

    SELECT c1, c1 <-> 'ababab'
     FROM test_trgm 
     ORDER BY c1 <-> 'ababab';
    

    サンプルデータを作成する

    -- Create some temporary data
    -- ! Note that table are created in tmp schema (change sql to your scheme) and deleted if exists !
    drop table if exists tmp.test_data;
    
    -- Random integer matrix 100*8 
    create table tmp.test_data as (
       select 
          trunc(random()*100)::int as input_variable_1,
          trunc(random()*100)::int as input_variable_2, 
          trunc(random()*100)::int as input_variable_3,
          trunc(random()*100)::int as input_variable_4, 
          trunc(random()*100)::int as input_variable_5, 
          trunc(random()*100)::int as input_variable_6, 
          trunc(random()*100)::int as input_variable_7, 
          trunc(random()*100)::int as input_variable_8
       from 
          generate_series(1,100,1)
    );
    

    入力データをテキストに変換する

    drop table if exists tmp.test_data_trans;
    
    create table tmp.test_data_trans as (
    select 
       input_variable_1 || ';' ||
       input_variable_2 || ';' ||
       input_variable_3 || ';' ||
       input_variable_4 || ';' ||
       input_variable_5 || ';' ||
       input_variable_6 || ';' ||
       input_variable_7 || ';' ||
       input_variable_8 as trans_variable
    from 
       tmp.test_data
    );
    

    これにより、1つの変数trans_variableが得られます 8つのディメンションすべてが保存されている場所:

    trans_variable
    40;88;68;29;19;54;40;90
    80;49;56;57;42;36;50;68
    29;13;63;33;0;18;52;77
    44;68;18;81;28;24;20;89
    80;62;20;49;4;87;54;18
    35;37;32;25;8;13;42;54
    8;58;3;42;37;1;41;49
    70;1;28;18;47;78;8;17
    

    ||の代わりに 演算子では、次の構文を使用することもできます(短くなりますが、よりわかりにくい):

    select 
       array_to_string(string_to_array(t.*::text,''),'') as trans_variable
    from 
       tmp.test_data t
    

    インデックスを追加

    create index test_data_gist_index on tmp.test_data_trans using gist(trans_variable);
    

    テスト距離注:テーブルから1つの行を選択しました-52;42;18;50;68;29;8;55 -わずかに変更された値を使用しました(42;42;18;52;98;29;8;55 )距離をテストします。もちろん、ランダム行列であるため、テストデータの値は完全に異なります。

    select 
       *, 
       trans_variable <->  '42;42;18;52;98;29;8;55' as distance,
       similarity(trans_variable, '42;42;18;52;98;29;8;55') as similarity,
    from 
       tmp.test_data_trans 
    order by
       trans_variable <-> '52;42;18;50;68;29;8;55';
    

    距離演算子<->または類似関数を使用できます。距離=1-類似性



    1. MySQLでデータベースリンクを作成してOracleに接続するにはどうすればよいですか?

    2. ユーザーがフィールドを定義できる場合のスキーマ設計

    3. MySQLAmazonRDSのバックアップ

    4. 単一のクエリでwhereフィルターを使用して30kのMySQLテーブルから3つのランダムレコードをすばやく選択するにはどうすればよいですか?