【问题标题】:PostgreSQL to iterate through rows and find the closest match using custom distance-functionPostgreSQL 遍历行并使用自定义距离函数找到最接近的匹配项
【发布时间】:2013-06-19 21:33:20
【问题描述】:

我是 PostgreSQL 新手,我的问题类似于这里的问题:link

例如,我有下表:

| id |       vector         |
|  1 |  { 1.43, 3.54, 5.55} |
|  2 |  { 4.46, 5.56, 4.55} |
|  3 |  { 7.48, 2.54, 4.55} |
|  4 |  { 2.44, 2.34, 4.55} |

一个类似于

的示例查询
SELECT * FROM my_table WHERE vector CLOSEST('{1.23, 4.43, 4.63}') 

应该以排序方式返回结果行,我使用自定义距离函数确定“最接近”的向量,例如calc_l2norm( double precision[], double precision[] ) 返回欧几里得距离。

【问题讨论】:

  • 那么,最接近的意思是参考向量的尖端与数据库中存储的尖端之间的最小距离?
  • 是的。计算查询向量与数据库中所有向量的距离。

标签: postgresql


【解决方案1】:

一般来说,您可以使用存储函数来解决这类问题,该函数是用 Java 或 Scala 编写的(有些人可能更喜欢 PL/SQL、C 或 C++)。

PostgreSql 支持(基于 Java 的)存储函数,因此让 SQL 查询获取数据,并将其传递给存储函数。存储的函数返回距离,因此您可以对其进行过滤/排序等。

基于这样的表

create table point(vector float8[]);
insert into point values('{0.0, 0.0, 0.0}');
insert into point values('{0.5, 0.5, 0.5}');

使用这样的 Java 函数:

public class PlJava {
    public final static double distance2(double[] v1, double[] v2) {
        return Math.sqrt(Math.pow(v2[0] - v1[0], 2)
          + Math.pow(v2[1] - v1[1], 2) + Math.pow(v2[2] - v1[2], 2));
    }
}

以及SQL中的函数声明:

CREATE FUNCTION pljava.distance2(float8[], float8[])
  RETURNS float8
  AS 'PlJava.distance2'
  IMMUTABLE
  LANGUAGE java;

您的查询可能如下所示:

select
    point.*, 
    pljava.distance2(vector, '{1.0, 1.0, 1.0}') as dist
  from
    point 
  order by
    dist;    

导致

    vector     |       dist  
---------------+-------------------  
 {0.5,0.5,0.5} | 0.866025403784439  
 {0,0,0}       |  1.73205080756888  

更新

存储函数也可以用 C 和 C++ 编写。 C++ 需要更多的努力,因为 PostgreSql 的接口使用 C 调用约定。见Using C++ for Extensibility

【讨论】:

  • 哈哈,Java 的东西很有趣(你能用 C++ 做同样的事情吗?)。我知道您可以使用 C 来完成,因为您可以在 pgAdmin 工具中编写函数定义时选择“C”作为语言。但这很有用,因为我打算使用更复杂的距离函数。
  • 是的,在 C 和 C++ 中也是可能的;我已经更新了答案。
【解决方案2】:

PostgresQL 具有最近邻索引功能

http://wiki.postgresql.org/wiki/What%27s_new_in_PostgreSQL_9.1#K-Nearest-Neighbor_Indexing

它可以与 PostgreSQL 或 PostGIS 一起使用,是 PostgreSQL 的 GIS 扩展。见

K-Nearest Neighbor Query in PostGIS

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多