PostgreSQL 家谱、族谱类应用实践 - 图式关系存储与搜索

本文涉及的产品
RDS PostgreSQL Serverless,0.5-4RCU 50GB 3个月
推荐场景:
对影评进行热评分析
云原生数据库 PolarDB 分布式版,标准版 2核8GB
云数据库 RDS SQL Server,基础系列 2核4GB
简介:

标签

PostgreSQL , 家谱 , 族谱 , 图式搜索


背景

最近《最强大脑》节目的国际PK赛中,来自谷歌的一位国际选手展示了他在谷歌时做的一套系统,把三国人物关系整理并展示成了一张大图,属于非常典型的图式应用。

pic

PostgreSQL非常适合于这类场景,有着丰富的SQL接口和良好的性能。下面这些都是PG在图式搜索方面的应用:

《小微贷款、天使投资(风控助手)业务数据库设计(图式搜索\图谱分析) - 阿里云RDS PostgreSQL, HybridDB for PostgreSQL最佳实践》

《金融风控、公安刑侦、社会关系、人脉分析等需求分析与数据库实现 - PostgreSQL图数据库场景应用》

《PostgreSQL 图式搜索(graph search)实践 - 百亿级图谱,毫秒响应》

《PostgreSQL 实践 - 内容社区(如论坛)图式搜索应用》

今天这篇文档与之类似,来自一位社区朋友的问题,如何存储家族关系,并快速提取N级信息。是不是和我之前写的社交类用户关系,风控类企业关系相似呢?

设计表结构

1、个人信息表,描述个人的详细信息、出生年月、住址、城市、等等。因为无法列举全个人的信息,所以我们可以用JSON来扩展这个等等,是不是很爽呢。

create table tbl_p_detail  -- 个人信息  
(  
  id int primary key,    -- 人物ID  
  info jsonb,            -- 人物描述  
  crt_time timestamp     -- 创建时间  
);  

2、关系的元数据表,例如父亲,母亲,丈夫,妻子,儿子,女儿,养女,继父,干爹,干女儿,等等。

create table tbl_er_desc  -- 关系描述  
(  
  id int2 primary key,    -- 关系ID  
  info text  -- 描述  
);  

3、关系表,这里面为了保证查询的准确性(或者说简化查询语句),我们使用双向冗余存储,例如父亲、儿子一对,存两条。

create table tbl_er     -- id1是id2的谁      
(  
  c1 int references tbl_p_detail(id),    
  c2 int references tbl_p_detail(id),    
  prop int2[],             -- 可能存在多种关系,我们使用数组存储。这个就是边,当然我们也可以用JSON来存储边。请参考我写的另一篇文档   
  crt_time timestamp,  
  check (c1<>c2),  
  unique (c1,c2)  
  -- FOREIGN KEY (EACH ELEMENT OF prop) REFERENCES tbl_er_desc(id)  -- 数组外键, PG 11会支持,很不错  
);  

4、创建索引加速

create index idx_tbl_er_c1 on tbl_er(c1);  
create index idx_tbl_er_c2 on tbl_er(c2);  

5、写入一些测试数据

pic

insert into tbl_p_detail select generate_series(1,10000);  
insert into tbl_er values (1,2,array[10],now());  -- 比如 1是2的父亲  
insert into tbl_er values (2,1,array[9],now());   -- 比如 2是1的女儿  
  
insert into tbl_er values (1,3,array[10],now());  -- 比如 1是3的父亲  
insert into tbl_er values (3,1,array[9],now());   -- 比如 3是1的女儿  
  
insert into tbl_er values (5,2,array[11],now());  -- 比如 5是2的母亲  
insert into tbl_er values (2,5,array[9],now());   -- 比如 2是5的女儿  
  
insert into tbl_er values (5,3,array[11],now());  -- 比如 5是3的母亲  
insert into tbl_er values (3,5,array[9],now());   -- 比如 3是5的女儿  
  
  
insert into tbl_er values (4,1,array[10],now());  -- 比如 4是1的父亲  
insert into tbl_er values (1,4,array[8],now());   -- 比如 1是4的儿子  
  
insert into tbl_er values (6,5,array[10],now());  -- 比如 6是5的父亲  
insert into tbl_er values (5,6,array[9],now());   -- 比如 5是6的女儿  
  
insert into tbl_er values (7,1,array[11],now());  -- 比如 7是1的母亲  
insert into tbl_er values (1,7,array[8],now());   -- 比如 1是7的儿子  
  
insert into tbl_er values (8,5,array[11],now());  -- 比如 8是5的母亲  
insert into tbl_er values (5,8,array[9],now());   -- 比如 5是8的女儿  

定义搜索函数

1、搜索某个用户的N层关系数据,以及每一层的限制记录数。(通常家族数据不会那么恐怖,所以限制层级即可,每一层输出所有也无所谓)

create or replace function graph_search1(      
  IN i_root int,                       -- 根据哪个节点开始搜        
  IN i_depth int  default 99999,       -- 搜索层级、深度限制      
  IN i_limit int8 default 2000000000,  -- 限制每一层返回的记录数      
  OUT o_path int[],                    -- 输出:路径, ID 组成的数组      
  OUT o_point1 int,                    -- 输出:点1 ID      
  OUT o_point2 int,                    -- 输出:点2 ID      
  OUT o_link_prop int2[],              -- 输出:当前两点之间的连接属性      
  OUT o_link_prop_all text,            -- 输出:从开始到当前点的连接属性      
  OUT o_depth int                      -- 输出:当前深度、层级      
) returns setof record as $$      
declare      
  sql text;      
begin      
sql := format($_$      
WITH RECURSIVE search_graph(        
  c1,     -- 点1        
  c2,     -- 点2        
  prop,   -- 当前边的属性      
  all_prop,  -- all 边的属性  
  depth,  -- 当前深度,从1开始         
  path    -- 路径,数组存储         
) AS (        
        select c1,c2,prop,all_prop,depth,path from (        
        SELECT                               -- ROOT节点查询        
          g.c1,                              -- 点1        
          g.c2,                              -- 点2        
          g.prop,                            -- 边的属性        
	  g.prop::text as all_prop,          -- all 边的属性  
          1 depth,                           -- 初始深度=1        
          ARRAY[g.c1, g.c2] path             -- 初始路径        
        FROM tbl_er AS g         
        WHERE         
          c1 = %s                            -- ROOT节点=?        
          limit %s                           -- 每个层级限制多少条?        
        ) t        
      UNION ALL        
        select c1,c2,prop,all_prop,depth,path from (        
        SELECT                               -- 递归子句         
          g.c1,                              -- 点1        
          g.c2,                              -- 点2        
          g.prop,                            -- 边的属性     
	  sg.all_prop || g.prop::text as all_prop,    -- all 边的属性  
          sg.depth + 1 depth,                   -- 深度+1        
          sg.path || g.c2 path                 -- 路径中加入新的点        
        FROM tbl_er AS g, search_graph AS sg    -- 循环 INNER JOIN        
        WHERE         
          g.c1 = sg.c2                       -- 递归JOIN条件        
          AND (g.c2 <> ALL(sg.path))                      -- 防止循环     , 是否循环,判断新点是否已经在之前的路径中   
          AND sg.depth <= %s                 -- 搜索深度=?          
          limit %s                           -- 每个层级限制多少条?       
        ) t        
)        
SELECT path as o_path, c1 as o_point1, c2 as o_point2, prop as o_link_prop, all_prop as o_link_prop_all, depth as o_depth      
FROM search_graph;                           -- 查询递归表,可以加LIMIT输出,也可以使用游标       
$_$, i_root, i_limit, i_depth, i_limit      
);      
      
return query execute sql;      
      
end;      
$$ language plpgsql strict;    

例子

postgres=# select * from graph_search1(1);  
  o_path   | o_point1 | o_point2 | o_link_prop | o_link_prop_all | o_depth   
-----------+----------+----------+-------------+-----------------+---------  
 {1,2}     |        1 |        2 | {10}        | {10}            |       1  
 {1,3}     |        1 |        3 | {10}        | {10}            |       1  
 {1,4}     |        1 |        4 | {8}         | {8}             |       1  
 {1,7}     |        1 |        7 | {8}         | {8}             |       1  
 {1,2,5}   |        2 |        5 | {9}         | {10}{9}         |       2  
 {1,3,5}   |        3 |        5 | {9}         | {10}{9}         |       2  
 {1,2,5,8} |        5 |        8 | {9}         | {10}{9}{9}      |       3  
 {1,2,5,6} |        5 |        6 | {9}         | {10}{9}{9}      |       3  
 {1,2,5,3} |        5 |        3 | {11}        | {10}{9}{11}     |       3  
 {1,3,5,8} |        5 |        8 | {9}         | {10}{9}{9}      |       3  
 {1,3,5,6} |        5 |        6 | {9}         | {10}{9}{9}      |       3  
 {1,3,5,2} |        5 |        2 | {11}        | {10}{9}{11}     |       3  
(12 rows)  
  
Time: 1.120 ms  

2、定义类似的搜索函数,但是返回游标。(家族图谱关系没有那么多,所以不需要游标返回,如果是社交类图谱,数据量大,建议用游标返回。)

create or replace function graph_search2(      
  IN i_root int,                       -- 根据哪个节点开始搜        
  IN i_res name,                       -- 游标名      
  IN i_depth int  default 99999,       -- 搜索层级、深度限制      
  IN i_limit int8 default 2000000000   -- 限制每一层返回的记录数      
) returns refcursor as $$      
declare      
  sql text;      
  res refcursor := i_res;      
begin      
sql := format($_$      
WITH RECURSIVE search_graph(        
  c1,     -- 点1        
  c2,     -- 点2        
  prop,   -- 当前边的属性     
  all_prop,  -- all 边的属性   
  depth,  -- 当前深度,从1开始         
  path   -- 路径,数组存储         
) AS (        
        select c1,c2,prop,all_prop,depth,path from (        
        SELECT                               -- ROOT节点查询        
          g.c1,                              -- 点1        
          g.c2,                              -- 点2        
          g.prop,                            -- 边的属性      
	  g.prop::text as all_prop,          -- all 边的属性	    
          1 depth,                           -- 初始深度=1        
          ARRAY[g.c1, g.c2] path             -- 初始路径    
        FROM tbl_er AS g         
        WHERE         
          c1 = %s                            -- ROOT节点=?        
          limit %s                           -- 每个层级限制多少条?        
        ) t        
      UNION ALL        
        select c1,c2,prop,all_prop,depth,path from (        
        SELECT                               -- 递归子句         
          g.c1,                              -- 点1        
          g.c2,                              -- 点2        
          g.prop,                            -- 边的属性        
	  sg.all_prop || g.prop::text as all_prop,    -- all 边的属性  
          sg.depth + 1 depth,                -- 深度+1        
          sg.path || g.c2 path                 -- 路径中加入新的点          
        FROM tbl_er AS g, search_graph AS sg      -- 循环 INNER JOIN        
        WHERE         
          g.c1 = sg.c2                       -- 递归JOIN条件        
          AND (g.c2 <> ALL(sg.path))         -- 防止循环 , 是否循环,判断新点是否已经在之前的路径中        
          AND sg.depth <= %s                 -- 搜索深度=?          
          limit %s                           -- 每个层级限制多少条?                   
        ) t        
)        
SELECT path as o_path, c1 as o_point1, c2 as o_point2, prop as o_link_prop, all_prop as o_link_prop_all, depth as o_depth      
FROM search_graph;                           -- 查询递归表,可以加LIMIT输出,也可以使用游标       
$_$, i_root, i_limit, i_depth, i_limit      
);      
      
open res for execute sql;      
return res;      
      
end;      
$$ language plpgsql strict;      

使用举例

postgres=# begin;  
BEGIN  
Time: 0.096 ms  
postgres=# select * from graph_search2(1,'a');  
 graph_search2   
---------------  
 a  
(1 row)  
  
Time: 1.110 ms  
postgres=# fetch 10 from a;  
  o_path   | o_point1 | o_point2 | o_link_prop | o_link_prop_all | o_depth   
-----------+----------+----------+-------------+-----------------+---------  
 {1,2}     |        1 |        2 | {10}        | {10}            |       1  
 {1,3}     |        1 |        3 | {10}        | {10}            |       1  
 {1,4}     |        1 |        4 | {8}         | {8}             |       1  
 {1,7}     |        1 |        7 | {8}         | {8}             |       1  
 {1,2,5}   |        2 |        5 | {9}         | {10}{9}         |       2  
 {1,3,5}   |        3 |        5 | {9}         | {10}{9}         |       2  
 {1,2,5,8} |        5 |        8 | {9}         | {10}{9}{9}      |       3  
 {1,2,5,6} |        5 |        6 | {9}         | {10}{9}{9}      |       3  
 {1,2,5,3} |        5 |        3 | {11}        | {10}{9}{11}     |       3  
 {1,3,5,8} |        5 |        8 | {9}         | {10}{9}{9}      |       3  
(10 rows)  
  
Time: 0.256 ms  
  
postgres=# fetch 10 from a;  
  o_path   | o_point1 | o_point2 | o_link_prop | o_link_prop_all | o_depth   
-----------+----------+----------+-------------+-----------------+---------  
 {1,3,5,6} |        5 |        6 | {9}         | {10}{9}{9}      |       3  
 {1,3,5,2} |        5 |        2 | {11}        | {10}{9}{11}     |       3  
(2 rows)  
  
Time: 0.103 ms  

3、定义两点的最短路径,比如搜索张三与李四的关系。当关系超过N级时,不返还,以免出现长时间搜索。(当然,我们也可以定义语句超时,当执行时间超过N秒后退出)

create or replace function graph_search3(      
  IN i_p1 int,                       -- 节点1        
  IN i_p2 int,                       -- 节点2        
  IN i_depth int  default 99999,     -- 搜索层级、深度限制        
  OUT o_path int[],                    -- 输出:路径, ID 组成的数组      
  OUT o_link_prop text,                -- 输出:当前两点之间的连接属性      
  OUT o_depth int                      -- 输出:当前深度、层级      
) returns record as $$      
declare      
  sql text;      
begin      
sql := format($_$      
WITH RECURSIVE search_graph(        
  c1,   -- 点1        
  c2,   -- 点2        
  prop, -- 边的属性        
  depth, -- 深度,从1开始        
  path  -- 路径,数组存储            
) AS (        
        SELECT    -- ROOT节点查询        
          g.c1,   -- 点1        
          g.c2,   -- 点2        
          g.prop::text,   -- 边的属性        
          1 depth,        -- 初始深度=1        
          ARRAY[g.c1, g.c2] path             -- 初始路径        
        FROM tbl_er AS g         
        WHERE         
          c1 = %s         -- ROOT节点=?      --(最短路径的起点)        
      UNION ALL        
        SELECT     -- 递归子句        
          g.c1,    -- 点1        
          g.c2,    -- 点2        
          sg.prop::text || g.prop::text,          -- 边的属性        
          sg.depth + 1 as depth,    -- 深度+1        
          sg.path || g.c2 path                 -- 路径中加入新的点      
        FROM tbl_er AS g, search_graph AS sg   -- 循环 INNER JOIN        
        WHERE         
          g.c1 = sg.c2         -- 递归JOIN条件        
          AND (g.c2 <> ALL(sg.path))        -- 防止循环 , 是否循环,判断新点是否已经在之前的路径中          
          AND sg.depth <= %s    -- 搜索深度=?        
    
)        
SELECT      
  path as o_path,    
  prop as o_link_prop,    
  depth as o_depth    
FROM search_graph        
  where c2 = %s   -- 最短路径的终点        
  limit 1         -- 查询递归表,可以加LIMIT输出,也可以使用游标        
$_$, i_p1, i_depth, i_p2);    
    
execute sql into o_path,o_link_prop,o_depth;    
return;    
end;    
$$ language plpgsql strict;    

使用举例

postgres=# select * from graph_search3(1,2);  
 o_path | o_link_prop | o_depth   
--------+-------------+---------  
 {1,2}  | {10}        |       1  
(1 row)  
  
Time: 0.907 ms  
postgres=# select * from graph_search3(1,5);  
 o_path  | o_link_prop | o_depth   
---------+-------------+---------  
 {1,2,5} | {10}{9}     |       2  
(1 row)  
  
Time: 0.854 ms  
postgres=# select * from graph_search3(1,8);  
  o_path   | o_link_prop | o_depth   
-----------+-------------+---------  
 {1,2,5,8} | {10}{9}{9}  |       3  
(1 row)  

扩展一些关系,再度搜索

insert into tbl_er values (2,3,array[12],now());  -- 比如 2是3的姐姐  
insert into tbl_er values (3,2,array[13],now());  -- 比如 3是2的妹妹  
postgres=# select * from graph_search1(1);  
   o_path    | o_point1 | o_point2 | o_link_prop | o_link_prop_all | o_depth   
-------------+----------+----------+-------------+-----------------+---------  
 {1,2}       |        1 |        2 | {10}        | {10}            |       1  
 {1,3}       |        1 |        3 | {10}        | {10}            |       1  
 {1,4}       |        1 |        4 | {8}         | {8}             |       1  
 {1,7}       |        1 |        7 | {8}         | {8}             |       1  
 {1,2,3}     |        2 |        3 | {12}        | {10}{12}        |       2  
 {1,2,5}     |        2 |        5 | {9}         | {10}{9}         |       2  
 {1,3,2}     |        3 |        2 | {13}        | {10}{13}        |       2  
 {1,3,5}     |        3 |        5 | {9}         | {10}{9}         |       2  
 {1,2,3,5}   |        3 |        5 | {9}         | {10}{12}{9}     |       3  
 {1,2,5,8}   |        5 |        8 | {9}         | {10}{9}{9}      |       3  
 {1,2,5,6}   |        5 |        6 | {9}         | {10}{9}{9}      |       3  
 {1,2,5,3}   |        5 |        3 | {11}        | {10}{9}{11}     |       3  
 {1,3,2,5}   |        2 |        5 | {9}         | {10}{13}{9}     |       3  
 {1,3,5,8}   |        5 |        8 | {9}         | {10}{9}{9}      |       3  
 {1,3,5,6}   |        5 |        6 | {9}         | {10}{9}{9}      |       3  
 {1,3,5,2}   |        5 |        2 | {11}        | {10}{9}{11}     |       3  
 {1,2,3,5,8} |        5 |        8 | {9}         | {10}{12}{9}{9}  |       4  
 {1,2,3,5,6} |        5 |        6 | {9}         | {10}{12}{9}{9}  |       4  
 {1,3,2,5,8} |        5 |        8 | {9}         | {10}{13}{9}{9}  |       4  
 {1,3,2,5,6} |        5 |        6 | {9}         | {10}{13}{9}{9}  |       4  
(20 rows)  
  
postgres=# select * from graph_search1(3);  
   o_path    | o_point1 | o_point2 | o_link_prop | o_link_prop_all | o_depth   
-------------+----------+----------+-------------+-----------------+---------  
 {3,1}       |        3 |        1 | {9}         | {9}             |       1  
 {3,5}       |        3 |        5 | {9}         | {9}             |       1  
 {3,2}       |        3 |        2 | {13}        | {13}            |       1  
 {3,1,7}     |        1 |        7 | {8}         | {9}{8}          |       2  
 {3,1,4}     |        1 |        4 | {8}         | {9}{8}          |       2  
 {3,1,2}     |        1 |        2 | {10}        | {9}{10}         |       2  
 {3,5,8}     |        5 |        8 | {9}         | {9}{9}          |       2  
 {3,5,6}     |        5 |        6 | {9}         | {9}{9}          |       2  
 {3,5,2}     |        5 |        2 | {11}        | {9}{11}         |       2  
 {3,2,5}     |        2 |        5 | {9}         | {13}{9}         |       2  
 {3,2,1}     |        2 |        1 | {9}         | {13}{9}         |       2  
 {3,1,2,5}   |        2 |        5 | {9}         | {9}{10}{9}      |       3  
 {3,5,2,1}   |        2 |        1 | {9}         | {9}{11}{9}      |       3  
 {3,2,5,8}   |        5 |        8 | {9}         | {13}{9}{9}      |       3  
 {3,2,5,6}   |        5 |        6 | {9}         | {13}{9}{9}      |       3  
 {3,2,1,7}   |        1 |        7 | {8}         | {13}{9}{8}      |       3  
 {3,2,1,4}   |        1 |        4 | {8}         | {13}{9}{8}      |       3  
 {3,1,2,5,8} |        5 |        8 | {9}         | {9}{10}{9}{9}   |       4  
 {3,1,2,5,6} |        5 |        6 | {9}         | {9}{10}{9}{9}   |       4  
 {3,5,2,1,7} |        1 |        7 | {8}         | {9}{11}{9}{8}   |       4  
 {3,5,2,1,4} |        1 |        4 | {8}         | {9}{11}{9}{8}   |       4  
(21 rows)  

参考

《小微贷款、天使投资(风控助手)业务数据库设计(图式搜索\图谱分析) - 阿里云RDS PostgreSQL, HybridDB for PostgreSQL最佳实践》

《金融风控、公安刑侦、社会关系、人脉分析等需求分析与数据库实现 - PostgreSQL图数据库场景应用》

《PostgreSQL 图式搜索(graph search)实践 - 百亿级图谱,毫秒响应》

《PostgreSQL 实践 - 内容社区(如论坛)图式搜索应用》

https://www.postgresql.org/docs/10/static/queries-with.html

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
1月前
|
存储 关系型数据库 数据库
【赵渝强老师】PostgreSQL的逻辑存储结构
PostgreSQL的逻辑存储结构包括数据库集群、数据库、表空间、段、区、块等。每个对象都有唯一的对象标识符OID,并存储于相应的系统目录表中。集群由单个服务器实例管理,包含多个数据库、用户及对象。表空间是数据库的逻辑存储单元,用于组织逻辑相关的数据结构。段是分配给表、索引等逻辑结构的空间集合,区是段的基本组成单位,而块则是最小的逻辑存储单位。
【赵渝强老师】PostgreSQL的逻辑存储结构
|
24天前
|
存储 SQL 关系型数据库
【赵渝强老师】PostgreSQL的物理存储结构
PostgreSQL在初始化时通过环境变量$PGDATA指定的目录下生成各类文件,构成其物理存储结构,包括数据文件、日志文件(如运行日志、WAL预写日志、事务日志和服务器日志)、控制文件及参数文件等,确保数据库的高效运行与数据安全。
|
6月前
|
自然语言处理 关系型数据库 数据库
技术经验解读:【转】PostgreSQL的FTI(TSearch)与中文全文索引的实践
技术经验解读:【转】PostgreSQL的FTI(TSearch)与中文全文索引的实践
74 0
|
7月前
|
存储 JSON 关系型数据库
PostgreSQL Json应用场景介绍和Shared Detoast优化
PostgreSQL Json应用场景介绍和Shared Detoast优化
|
7月前
|
SQL 运维 关系型数据库
基于AnalyticDB PostgreSQL的实时物化视图研发实践
AnalyticDB PostgreSQL版提供了实时物化视图功能,相较于普通(非实时)物化视图,实时物化视图无需手动调用刷新命令,即可实现数据更新时自动同步刷新物化视图。当基表发生变化时,构建在基表上的实时物化视图将会自动更新。AnalyticDB PostgreSQL企业数据智能平台是构建数据智能的全流程平台,提供可视化实时任务开发 + 实时数据洞察,让您轻松平移离线任务,使用SQL和简单配置即可完成整个实时数仓的搭建。
144011 8
|
7月前
|
弹性计算 关系型数据库 数据库
开源PostgreSQL在倚天ECS上的最佳优化实践
本文基于倚天ECS硬件平台,以自顶向下的方式从上层应用、到基础软件,再到底层芯片硬件,通过应用与芯片的硬件特性的亲和性分析,实现PostgreSQL与倚天芯片软硬协同的深度优化,充分使能倚天硬件性能,帮助开源PostgreSQL应用实现性能提升。
|
7月前
|
关系型数据库 数据库 PostgreSQL
Docker【应用 03】给Docker部署的PostgreSQL数据库安装PostGIS插件(安装流程及问题说明)
Docker【应用 03】给Docker部署的PostgreSQL数据库安装PostGIS插件(安装流程及问题说明)
457 0
|
7月前
|
关系型数据库 数据库 PostgreSQL
PostgreSQL【应用 01】使用Vector插件实现向量相似度查询(Docker部署的PostgreSQL安装pgvector插件说明)和Milvus向量库对比
PostgreSQL【应用 01】使用Vector插件实现向量相似度查询(Docker部署的PostgreSQL安装pgvector插件说明)和Milvus向量库对比
671 1
|
7月前
|
SQL 关系型数据库 C语言
PostgreSQL【应用 03】Docker部署的PostgreSQL扩展SQL之C语言函数(编写、编译、载入)计算向量余弦距离实例分享
PostgreSQL【应用 03】Docker部署的PostgreSQL扩展SQL之C语言函数(编写、编译、载入)计算向量余弦距离实例分享
106 0
|
7月前
|
SQL 关系型数据库 数据库
PostgreSQL【应用 02】扩展SQL之C语言函数(编写、编译、载入)实例分享
PostgreSQL【应用 02】扩展SQL之C语言函数(编写、编译、载入)实例分享
239 0

相关产品

  • 云原生数据库 PolarDB
  • 云数据库 RDS PostgreSQL 版