在Postgresql中进行关键字查找

news/2024/7/9 19:32:25 标签: 1024程序员节, postgresql, 数据库

在Postgresql中通过关键字查询,一般情况下,利用like语句。比如:
select name from poi where name like '%key word%'.
但是众所周知,这样的匹配率不尽如人意。

本文通过示例,利用pg_trgm扩展进行实现更完美的关键字查询。

新建数据表如下:

-- public.t_poi definition
-- Drop table
-- DROP TABLE public.t_poi;
CREATE TABLE public.t_poi (
	id varchar NULL,    --唯一标示
	pname varchar NULL, --名称
	dtype varchar NULL, --类别
	address varchar NULL--地址
);

默认表中的数据存储了上千万条记录。

假设其中有如下数据:

SELECT name as pname,dtype,address FROM public.t_poi;

pname                    |dtype             |address                  |
-------------------------+------------------+-------------------------+
黑龙江广播电视网络股份有限公司(通河分公司营业厅)|生活服务;生活服务场所;生活服务场所|建安路与民强街交叉口东北50米通河县广播电视台附近|
闻名劳务咨询公司                 |生活服务;中介机构;中介机构    |通河镇长安街隆泰小区1号楼门市          |
四达劳务信息咨询通河分公司            |生活服务;人才市场;人才市场    |向阳街百合名苑小区4门市             |
黑龙江隆凯房地产估价有限公司           |生活服务;事务所;评估事务所    |隆达路1号附近                  |
哈尔滨旭苑会计服务公司              |生活服务;事务所;会计师事务所   |园丁公寓北门东侧                 |
哈工工具销售公司                 |购物服务;家居建材市场;建材五金市场|南马路86|
哈通物流有限公司                 |生活服务;物流速递;物流速递    |中央大街6号附近                 |
刚子保洁服务公司                 |生活服务;中介机构;中介机构    |金街40|
东讯劳务输出公司                 |生活服务;人才市场;人才市场    |通河镇隆达路大千市场道南中通速递对面       |
神舟线缆有限公司                 |购物服务;家居建材市场;建材五金市场|景阳街140|

使用like查询包含"夕阳"关键字的记录,语句可能如下

SELECT * FROM public.t_poi WHERE PNAME LIKE '%夕阳红%老年%公寓%';
pname              |dtype            |address          |
-------------------+-----------------+-----------------+
延寿夕阳红老年公寓          |体育休闲服务;度假疗养场所;疗养院|东新华街与爱民南胡同交叉口北50|
夕阳红老年公寓(通河县红十字医院西北)|体育休闲服务;度假疗养场所;疗养院|中央大街(通河县红十字医院西北) |
道里区夕阳红老年公寓         |体育休闲服务;度假疗养场所;疗养院|安静街104-2|
夕阳红老年公寓(清园东)       |体育休闲服务;度假疗养场所;疗养院|信恒现代城文园B栋7门市     |
夕阳红老年公寓            |体育休闲服务;度假疗养场所;疗养院|果园星城a区111|
夕阳红老年公寓(信恒现代城东北)   |体育休闲服务;度假疗养场所;疗养院|信恒现代城文园b栋7门市     |
夕阳红老年公寓            |体育休闲服务;度假疗养场所;疗养院|团结路方正镇政府东南100|

pg_trgm的方法如下:
先安装扩展:

CREATE EXTENSION pg_trgm;  

此时查询可以变为如下方式:

SELECT name as pname,dtype,address FROM  public.t_poi ORDER BY (name <->'夕阳红老年公寓') limit 10;
pname              |dtype             |address          |
-------------------+------------------+-----------------+
夕阳红老年公寓            |体育休闲服务;度假疗养场所;疗养院 |果园星城a区111|
夕阳红老年公寓            |体育休闲服务;度假疗养场所;疗养院 |团结路方正镇政府东南100|
夕阳红老年公寓(清园东)       |体育休闲服务;度假疗养场所;疗养院 |信恒现代城文园B栋7门市     |
夕阳红老年公寓(信恒现代城东北)   |体育休闲服务;度假疗养场所;疗养院 |信恒现代城文园b栋7门市     |
夕阳老年公寓             |体育休闲服务;度假疗养场所;疗养院 |延川大街146|
延寿夕阳红老年公寓          |体育休闲服务;度假疗养场所;疗养院 |东新华街与爱民南胡同交叉口北50|
道里区夕阳红老年公寓         |体育休闲服务;度假疗养场所;疗养院 |安静街104-2|
鑫阳红老年公寓            |体育休闲服务;度假疗养场所;疗养院 |丁香街与金街交叉口西北50|
夕阳红老年公寓(通河县红十字医院西北)|体育休闲服务;度假疗养场所;疗养院 |中央大街(通河县红十字医院西北) |
夕阳红老年服务站           |生活服务;生活服务场所;生活服务场所|新疆街道新祥里街劳动局家属楼61|

在实际查找中,可能在pname,dtype,address三列同时查找,所以创建索引如下:

CREATE INDEX idx_poi_similarity 
    ON public.t_poi USING 
    gist (((((pname)::text || (dtype)::text) || (address)::text)) gist_trgm_ops);

由于<->方法类似与近似值计算,所如果被查找列如果比较长的情况下,查找结果可能不尽如人意。

所以结合实际情况对查询进行优化:

select pname,dtype,address from
(
	select distinct * from 
	(
	    --完全包含是我们期望的结果,但是相似度却不一定很高
	    --比如字段中存储了100个字符,搜索的只有两个字符
	    --相似性相比于和搜索结果长度一样,但是只有一个字符差异的记录要低
	    --所以我们先查找包含的记录。
		(select name as pname,dtype,address,0 as OD from public.t_poi pd where strpos(name||dtype||address,'夕阳红老年公寓') > 0 limit 10)
		union all
		(select name as pname,dtype,address,1 as OD from public.t_poi pd order by (name||dtype||address <-> '夕阳红老年公寓') limit 10)
	) a 
) x  limit 10;
pname           |dtype             |address          |
----------------+------------------+-----------------+
夕阳红老年服务站        |生活服务;生活服务场所;生活服务场所|新疆街道新祥里街劳动局家属楼61|
夕阳红老年公寓         |体育休闲服务;度假疗养场所;疗养院 |果园星城a区111|
夕阳红老年公寓         |体育休闲服务;度假疗养场所;疗养院 |果园星城a区111|
夕阳红老年公寓         |体育休闲服务;度假疗养场所;疗养院 |团结路方正镇政府东南100|
夕阳红老年公寓(信恒现代城东北)|体育休闲服务;度假疗养场所;疗养院 |信恒现代城文园b栋7门市     |
夕阳红牙齿美容         |医疗保健服务;诊所;诊所      |庆木公路西50|
夕阳红老年公寓(清园东)    |体育休闲服务;度假疗养场所;疗养院 |信恒现代城文园B栋7门市     |
道里区夕阳红老年公寓      |体育休闲服务;度假疗养场所;疗养院 |安静街104-2|
道里区夕阳红老年公寓      |体育休闲服务;度假疗养场所;疗养院 |安静街104-2|
夕阳红老年公寓(信恒现代城东北)|体育休闲服务;度假疗养场所;疗养院 |信恒现代城文园b栋7门市     |

关于pg_trgm的详情,请查看pg_trgm。


http://www.niftyadmin.cn/n/5117421.html

相关文章

代码随想录图论 第一天 | 797.所有可能的路径 200. 岛屿数量

代码随想录图论 第一天 | 797.所有可能的路径 200. 岛屿数量 一、797.所有可能的路径 题目链接&#xff1a;https://leetcode.cn/problems/all-paths-from-source-to-target/ 思路&#xff1a;求从0到n-1的所有路径&#xff0c;终止条件是当前节点为n-1。本题图的结构是group…

react中使用监听

在 React 中&#xff0c;您可以使用 addEventListener 函数来监听事件。以下是一个示例&#xff1a; import React, { useRef, useEffect } from react;function App() {const inputRef useRef(null);useEffect(() > {inputRef.current.addEventListener(input, handleInp…

空运知识之常用空运名词

ATA/ATD (Actual Time of Arrival / Actual Time of Departure)实际到港/离港时间的缩写。 航空货运单 (AWB) (Air Waybill)由托运人或以托运人名义签发的单据&#xff0c;是托运人和承运人之间货物运输的证明。 无人陪伴行李(Baggage, Unaccompanied)非随身携带而经托运的行…

分享一下商城小程序怎么设置分销功能

随着互联网的快速发展&#xff0c;传统的营销方式已经无法满足企业的需求。在这个时代&#xff0c;拥有一个高效的分销系统已经成为了企业成功的关键之一。而商城小程序作为近年来火爆的电商新模式&#xff0c;其中的分销功能更是备受关注。本文将以分销功能为主要主题&#xf…

LInux系统编程(3)

取得拓展属性 #include <sys/types.h> #include <attr/xattr.h>ssize_t getxattr(const char* path, const char* key, void* value, size_t size); ssize_t lgetxattr(const char* path, const char* key, void* value, size_t size); ssize_t fgetxattr(int fd,…

【RTOS学习】同步与互斥 | 队列 | 队列集

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《RTOS学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 同步与互斥 | 队列 | 队列集 &#x1f349;同步与互斥&#x1f9ca;同步&#x1f9ca;互斥 &#…

怎么保护公司文件安全

怎么保护公司文件安全 无纸化办公时代&#xff0c;无论是企业还是个人在生活的方方面面都依赖于对电子化软件以及设备的使用。尤其是对于企业而言&#xff0c;在日常办公中产生的相关电子文件都是以电子文档的形式存储在电脑上。 下载试用安企神数据防泄密软件 若企业未实施…

使用IO流完成项目实战水果库存系统

以下内容本人都是在 Maven 工程下总结的 需求介绍显示主菜单让程序无线运行下去加载数据显示库存列表根据名称查找特定库存记录添加库存记录查看_下架_退出功能实现持久化数据 / 钝化&#xff1a;将 内存 里的数据持久化存储到 硬盘 IO流 package com.csdn.fruit.pojo; import…