基于Postgresql的低成本简单搜索

postgresql具有full text search(FTS),可以实现全文检索,也有GIN(倒排索引),可以实现比较简单的搜索场景(如标签搜索,文本搜索)。

相比like等老旧的搜索功能,full text search 有如下优势:

  1. 单词归一化
  2. 具有排序功能
  3. 速度快,不需要遍历所有文档

成本比较

4核32G,80G存储,带运维服务

ES集群:5万/年

PG集群实例:5千/年

性能比较

PG插入速度 2万条/秒

PG搜索速度 15ms(1000万行,limit 100)

ES插入速度 1万条/秒

ES搜索速度 250ms ~ 1500ms(1000万行,limit 100)(时间波动比较大)

数据库SQL实现

tsvector, tsquery的ts代表text search

FTS搜索

SELECT * FROM public.object_storage where tags @@ 'address_fixer & asr'

上述等价于

SELECT * FROM public.object_storage where tags @@ 'address_fixer & asr'::tsquery

SELECT * FROM public.object_storage where tags @@ tsquery('address_fixer & asr')  ----- 代码实现要使用这种

但不等于

SELECT * FROM public.object_storage where tags @@ to_tsquery('address_fixer & asr');

tsquery 不会对单词归一化,但是to_tsquery 会对单词归一化。

在标签场景,不建议做归一化。

tags列的数据类型为tsvector

@@等同于ES的match功能。

'address_fixer & asr' 代表必须匹配上 address_fixer 和 asr 2个词。 可以加入或 |  组成更复杂的逻辑组合。 

加入排序

排序细节参考:PostgreSQL: Documentation: 15: 12.3. Controlling Text Search

ts_rank(tags, query, 1) 的1(1 divides the rank by 1 + the logarithm of the document length),默认是0(不考虑文档长度,排序效果不佳)

SELECT * FROM object_storage, tsquery(:tag) query, ts_rank(tags, query, 1) rank_tags" +
        " WHERE bucket = :bucket AND tags @@ query ORDER BY rank_tags DESC

插入数据

insert into object_storage(bucket, object_name, tags) values(?, ?, tsvector(?))

标签搜索场景

虽然pg默认不支持中文分词,但输入的标签(不管中文还是英文)采用空格分割即可,默认按空格切分。

建立倒排索引提高查询速度

GIN是general inverted index 倒排索引的意思,可以提高搜索速度

CREATE INDEX tags_gin_index ON public.object_storage USING GIN (tags);

(GIN和GiST的索引选型,参考:GiST和GIN索引类型 )

TODO:tsquery的搜索权重

spring data jpa的代码实现

如何在spring data jpa中定义pg的tsvector类型?

spring data jpa是一个通用框架,有一些其他但又常用的类型,需要使用另一个库:

GitHub - vladmihalcea/hypersistence-utils: The Hypersistence Utils library (previously known as Hibernate Types) gives you Spring and Hibernate utilities that can help you get the most out of your data access layer.

里面有不同的文件夹,52代表java 8(55代表java11等)

如果公司只支持java8,所以需要选择52,版本号要尽量高,否则低版本会没有search的PostgreSQLTSVectorType类型

<dependency>
   <groupId>com.vladmihalcea</groupId>
   <artifactId>hibernate-types-52</artifactId>
   <version>2.16.0</version>
</dependency>

使用方法参见hibernate-types的github主页(6x系列和5x系列的使用方法不一样)

@Type(type = "com.vladmihalcea.hibernate.type.search.PostgreSQLTSVectorType")
@Column(columnDefinition = "tsvector")
private String tags;

如何查询?

需要基于自定义query实现。

注意:虽然pgadmin可以直接 tags @@ 'address_fixer & asr'

但是下面的是不能写为 tags @@ :tag 或 tags && ':tag' ,需要加to_tsquery()包裹起来

但是to_tsquery有一个弊端,就是会做归一化等处理,这在标签搜索,反而是弊端,举例address_fixer变成了address 和 fixer 2个独立的词,改变了输入。

@Query(value = "SELECT * FROM object_storage WHERE tags @@ to_tsquery(:tag)", nativeQuery = true)
List<ObjectStorageEntity> searchTags(@Param("tag") String tag);

minio的sdk

Java Client API Reference — MinIO Object Storage for Linux

参考文章

PostgreSQL: Documentation: 15: 8.11. Text Search Types 搜索数据类型:

PostgreSQL: Documentation: 15: 9.13. Text Search Functions and Operators 函数及操作符

PostgreSQL: Documentation: 15: 12.1. Introduction

GiST和GIN索引类型 索引选择(GIN, GiST)PostgreSQL实现全文检索 - 知乎  pg实现全文搜索

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值