【问题标题】:Postgresql k-nearest neighbor (KNN) on multidimensional cube多维立方体上的 Postgresql k-最近邻 (KNN)
【发布时间】:2013-05-16 14:41:32
【问题描述】:

我有一个有 8 个维度的立方体。我想做最近邻匹配。我对 postgresql 完全陌生。我读到 9.1 支持多维度上的最近邻匹配。如果有人能给出一个完整的例子,我真的很感激:

  1. 如何用 8D 立方体创建表格?

  2. 插入示例

  3. 查找 - 精确匹配

  4. 查找 - 最近邻匹配

样本数据:

为简单起见,我们可以假设所有值的范围都是 0-100。

点1:(1,1,1,1, 1,1,1,1)

点2:(2,2,2,2, 2,2,2,2)

查找值:(1,1,1,1, 1,1,1,2)

这应该匹配 Point1 而不是 Point2。

参考:

What's_new_in_PostgreSQL_9.1

https://en.wikipedia.org/wiki/K-d_tree#Nearest_neighbour_search

【问题讨论】:

  • 你能解释一下你有什么数据,也许提供一些小样本?我认为 8D 立方体只是一个有 8 列(维度)的表格。
  • 我编辑了问题以包含示例数据。是的,8D 立方体可以使用 8 个不同的数字列来表示。
  • 我在原始答案中添加了完整的示例。

标签: postgresql postgresql-9.1 nearest-neighbor


【解决方案1】:

最近在 pgsql-hackers 列表中提供了一个“patch that introduces kNN search for cubes with euclidean, taxicab and chebyshev distances”。如果您可以自定义 PostgreSQL 构建,它可能适合您的目的。

请注意,cube 类型是 PostgreSQL 扩展,可用于表示 n 维中的点或立方体。 (默认情况下,n 的值可以达到 100,如果提高了cubedata.h 中的限制,则可以达到更多。)因此,这个补丁应该启用索引辅助多维点/向量/立方体最近邻搜索。

(如果没有这个补丁,cube 类型没有<-> 距离运算符,并且OPERATOR CLASS gist_cube_ops 缺少支持功能(#8),这是使 gist 能够制作这些值的距离相关索引。)

我还没有尝试过这个补丁,并注意到讨论列表中的一个回复表明它目前可能会破坏一些回归测试。

【讨论】:

    【解决方案2】:

    PostgreSQL 支持距离运算符<->,据我了解,这可用于分析文本(使用 pg_trgrm 模块)和geometry 数据类型。

    我不知道如何将它用于超过 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
    

    然后到一列表格:

    c1
    abababac
    

    然后就可以使用了(创建gistindex之后):

    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
    );
    

    这将为您提供一个变量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);
    

    测试距离 注意:我从表中选择了一行 - 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 - 相似度

    【讨论】:

    • 谢谢 twn08。我在尝试创建索引时遇到了这个错误:create index test_data_gist_index on tmp.test_data_trans using gist(trans_variable);错误:数据类型文本没有访问方法“gist”的默认运算符类 SQL 状态:42704 提示:您必须为索引指定运算符类或为数据类型定义默认运算符类。
    • 也许btree_gist 不见了?类似问题in this question
    • 我没有看到您在分号连接的列中定义条目之间的距离度量。 算子是使用解码点的字符串距离还是几何距离?
    猜你喜欢
    • 2020-06-17
    • 2015-01-19
    • 1970-01-01
    • 1970-01-01
    • 2014-04-12
    • 2011-12-06
    • 2017-04-07
    • 2018-04-08
    • 2014-05-14
    相关资源
    最近更新 更多