Postgres中的多维距离

Ant*_*ham 3 postgresql postgis

Postgres / Postgis支持点之间的距离计算,按给定点的距离排序等等,我正在尝试滥用此功能:)

这是一个例子,只是为了说明我正在尝试做的事情。

       Width    Height  Thickness   Hue Lightness   Saturation     
Item1  220      157     100         270 60          75     
Item2  221      199     105         280 60          75     
Item3  210      150     105         100 40          75   
Run Code Online (Sandbox Code Playgroud)

现在忽略这些功能,从下表中查找在物理尺寸上相似的紧密匹配的项目,您可以执行以下操作:

SELECT * FROM items
ORDER BY sqrt((i1.width-i2.height)*(i1.width-i2.height)
            + (i1.width-i2.height)*(i1.width-i2.height)
            + (i1.thickness-i2.thickness)*(i1.thickness-i2.thickness))
Run Code Online (Sandbox Code Playgroud)

(调用该伪sql :))

我们可以将第4-6个属性视为尺寸,以使相似(或“接近”)颜色的每个属性具有相似的值。我们可以通过添加这些字段来扩展上述查询。

现在,Postgres似乎可以用索引做一些很棒的事情,这样可以大大加快上述查询的速度,但是数据类型似乎最多只能达到4维。

对于数百万条记录,以10个小数位(或“维数”)的记录相似度进行计算,并且更经常地对其排序,这将是一个好的解决方案?

我目前正在考虑3个4D点,并按3点的距离进行排序。

如果没有Postgis的东西,我想问题将是:

在具有以下各项的表中,将是利用10个输入值(每个val字段一个)之间的差值之和进行排序的最快方法,要尽可能利用边界框,空间或其他索引等。

例如。

SELECT * FROM items
ORDER BY ((item_val1-xxxx)*(item_val1-xxxx)
        * (item_val2-yyyy)*(item_val2-yyyy)
        * ......
        * (item_val10-zzzz)*(item_val10-zzzz))
Run Code Online (Sandbox Code Playgroud)

其中xxxx,yyyy,zzzz代表在前端应用程序中输入的值

item_name: string
item_val1: int
item_val2: int
item_val3: int
item_val4: int
item_val5: int
item_val6: int
item_val7: int
item_val8: int
item_val9: int
item_val10: int
Run Code Online (Sandbox Code Playgroud)

任何想法/替代品,不胜感激。

Mik*_*e T 6

PostGIS非常适合GIS,但正如John B所指出的那样,多维数据集扩展非常适合与n维欧氏距离。

添加扩展,并在表中添加带有GiST索引的新列:

CREATE EXTENSION cube;
ALTER TABLE items ADD COLUMN point cube;
CREATE INDEX items_point_idx ON items USING gist (point);
Run Code Online (Sandbox Code Playgroud)

填充该point字段,您可能希望通过将列乘以标量(2代表两次,0.5代表一半,依此类推)来使某些属性的权重高于其他属性:

UPDATE items SET
  point = cube(array[width, height, thickness, hue, lightness, saturation]);
Run Code Online (Sandbox Code Playgroud)

现在使用自联接找到一些距离:

SELECT i1.id, i1.point, i2.id, i2.point, cube_distance(i1.point, i2.point)
FROM items i1, items i2
WHERE i1.id < i2.id
ORDER BY cube_distance(i1.point, i2.point);
Run Code Online (Sandbox Code Playgroud)