译者 | 布加迪
审校 | 重楼
使用传统的何使合搜基于词汇(或基于关键字)的搜索,我们可以找到含有我们搜索的实索确切单词的文档。关键词搜索在准确性方面表现出色,现混但在替代词语或自然语言方面表现差强人意。何使合搜

语义搜索通过捕获文档和用户查询背后的实索意图来克服这些限制。这通常通过利用向量嵌入将文档和查询映射到高维空间,现混并计算向量相似性以检索相关结果来实现。何使合搜
针对几种系统,实索单一的现混搜索方法可能会失败,导致向用户显示不完整的何使合搜信息。结合上述两种搜索方法的实索优势将使我们能够提供出色的搜索体验。
Elasticsearch和Apache Solr等系统都很好地支持基于关键字的现混搜索。语义搜索通常需要使用向量数据库进行存储,何使合搜市面上有多种解决方案。实索这篇文章解释了我们如何在Postgres中使用单单一个熟悉的现混存储系统来支持包括词汇搜索和语义搜索的混合搜索。
假设我们有一个应用程序使用下面的表,允许用户通过关键字或自然语言搜索产品:
复制SQL CREATE TABLE products ( id bigserial PRIMARY KEY, description VARCHAR(255), embedding vector(384) );1.2.3.4.5.6.7.8.9.10.description列包含产品的文本/自然语言描述。Postgres在该列上为全文搜索提供了默认索引,但是我们也可以创建自定义索引以加速全文搜索,亿华云其作用类似信息检索的索引。
embedding列存储产品描述的向量(浮点)表示,捕获语义含义而不是单词。Postgres中的pgvector扩展带来了向量数据类型和向量相似性度量指标:L2、余弦和点积距离。有几种方法可以生成嵌入,比如使用词级嵌入(如Word2Vec)、句子/文档嵌入(如SBERT)或者来自基于Transformer的模型(如BERT模型)的嵌入。
为了演示,我们将在数据库中插入以下数据:
复制SQL INSERT INTO products (description) VALUES (Organic Cotton Baby Onesie - Newborn Size, Blue), (Soft Crib Sheet for Newborn, Hypoallergenic), (Baby Monitor with Night Vision and Two-Way Audio), (Diaper Bag Backpack with Changing Pad - Unisex Design), (Stroller for Infants and Toddlers, Lightweight), (Car Seat for Newborn, Rear-Facing, Extra Safe), (Baby Food Maker, Steamer and Blender Combo), (Toddler Sippy Cup, Spill-Proof, BPA-Free), (Educational Toys for 6-Month-Old Baby, Colorful Blocks), (Baby Clothes Set - 3 Pack, Cotton, 0-3 Months), (High Chair for Baby, Adjustable Height, Easy to Clean), (Baby Carrier Wrap, Ergonomic Design for Newborns), (Nursing Pillow for Breastfeeding, Machine Washable Cover), (Baby Bath Tub, Non-Slip, for Newborn and Infant), (Baby Skincare Products - Lotion, Shampoo, Wash - Organic);1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.针对嵌入,我使用了SentenceTransformer模型(又名SBERT)以生成嵌入,然后将它们存储在数据库中。下面的Python代码演示了这一点:
复制SQL descriptions = [product[1] for product in products] model = SentenceTransformer("all-MiniLM-L6-v2") embeddings = model.encode(descriptions) # Update the database with embeddings for i, product in enumerate(products): product_id = product[0] embedding = embeddings[i] # Convert to Python list # Construct the vector string representation embedding_str = str(embedding.tolist()) cur.execute("UPDATE products SET embedding = %s WHERE id = %s", (embedding_str, product_id)) # Commit changes and close connection conn.commit()1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16. 全文搜索Postgres为关键字搜索提供了广泛的开箱即用支持。我们可以为基于关键字的检索编写如下查询:
假设我们想要搜索婴儿睡眠用品。我们可以使用以下查询进行搜索:
复制SQL SELECT id, description FROM products WHERE description @@ to_tsquery(english, crib | baby | bed);1.2.3.4.这将返回以下产品:
复制SQL "Soft Crib Sheet for Newborn, Hypoallergenic"1.2.注意:ts_query搜索词素/标准化关键字,因此用newborns或babies替换newborn也会返回相同的结果。
当然,上面只是一个简单的例子,Postgres的全文搜索功能允许我们进行一番定制,比如跳过某些单词、源码库处理同义词、使用复杂的解析等,通过覆盖默认的文本搜索配置来实现。
虽然这些查询在没有索引的情况下也可以工作,但大多数应用程序发现这种方法太慢了,可能除了偶尔的临时搜索之外。文本搜索的实际应用通常需要创建索引。下面的代码演示了如何针对description列创建GIN索引(广义倒排索引),并使用它进行高效搜索。
复制SQL --Create a tsvector column (you can add this to your existing table) ALTER TABLE products ADD COLUMN description_tsv tsvector; --Update the tsvector column with indexed data from the description column UPDATE products SET description_tsv = to_tsvector(english, description); -- Create a GIN index on the tsvector column CREATE INDEX idx_products_description_tsv ON products USING gin(description_tsv);1.2.3.4.5.6.7.8.9.10.11.12. 语义搜索示例现在不妨尝试为我们的查询意图(“婴儿睡眠用品”)执行语义搜索请求。为此,我们计算嵌入(如上所述),并根据向量距离(在本例中为余弦距离)选择最相似的产品。下面的代码演示了这一点:
复制Python # The query string query_string = baby sleeping accessories # Generate embedding for the query string query_embedding = model.encode(query_string).tolist() # Construct the SQL query using the cosine similarity operator (<->) # Assuming you have an index that supports cosine similarity (e.g., ivfflat with vector_cosine_ops) sql_query = """ SELECT id, description, (embedding <-> %s::vector) as similarity FROM products ORDER BY similarity LIMIT 5; """ # Execute the query cur.execute(sql_query, (query_embedding,)) # Fetch and print the results results = cur.fetchall() for result in results: product_id, description, similarity = result print(f"ID: {product_id}, Description: {description}, Similarity: {similarity}") cur.close() conn.close()1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.这给了我们以下结果:
复制Plain Text ID: 12, Description: Baby Carrier Wrap, Ergonomic Design for Newborns, Similarity: 0.9956936200879117 ID: 2, Description: Soft Crib Sheet for Newborn, Hypoallergenic, Similarity: 1.0233573590998544 ID: 5, Description: Stroller for Infants and Toddlers, Lightweight, Similarity: 1.078171715208051 ID: 6, Description: Car Seat for Newborn, Rear-Facing, Extra Safe, Similarity: 1.08259154868697 ID: 3, Description: Baby Monitor with Night Vision and Two-Way Audio, Similarity: 1.09027342717840851.2.3.4.5.6.除了每个结果外,我们还返回了相似性(就余弦相似性而言越低越好)。正如我们所见,通过嵌入搜索,我们得到了更丰富的结果集,这很好地补充了基于关键字的搜索。
默认情况下,pgvector执行精确的最近邻搜索,网站模板保证完美的召回。然而,随着数据集大小增加,这种方法的成本相当高。我们可以添加一个索引,以召回换取速度。一个例子是Postgres中的IVFFlat(倒置文件与平面压缩)索引,其工作原理是,使用k-means聚类将向量空间划分为簇类。在搜索期间,它识别最接近查询向量的簇类,并在这些选定的簇类中执行线性扫描,计算查询向量与这些簇类中向量之间的精确距离。下面的代码定义了如何创建这样一个索引:
复制SQL CREATE INDEX ON products USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100); lists indicates the number of clusters to create. vector_cosine_ops indicates the distance metric we are using (cosine, inner product, or Euclidean/L2)1.2.3.4.5. 结果融合上述两种方法在不同的场景中表现出色,并相辅相成。将两种方法的结果结合起来有望得到稳健的搜索结果。倒数排序融合(RRF)是一种将多个具有不同相关指标的结果集组合成单个结果集的方法。RRF不需要调优,不同的相关指标也没必要相互关联才能获得高质量的结果。RRF的核心体现在其公式中:
Mathematica
RRF(d) = (r R) 1 / k + r(d))
其中
- d 是文档
- R 是排序器(检索器)集
- k 是常数(通常是60)
- r(d) 是排序器(r)中的文档(d)排序
在我们的例子中,我们将这样做:
1. 通过在添加一个常数后取其排序的倒数来计算每个结果集中每个产品的排序。这个常数可以防止排名靠前的产品主导最终得分,并允许排名较低的产品做出有意义的贡献。
2. 对来自所有结果集的排序倒数求和,以获得产品的最终RRF分数。
针对关键字搜索,Postgres提供了一个排序函数ts_rank(和一些变体),它可以用作结果集中产品的排序。针对语义搜索,我们可以使用嵌入距离来计算结果集中产品的排序。它可以用SQL来实现,使用每种搜索方法的CTE,最后将它们组合起来。
此外,我们还可以在合并后使用机器学习模型对结果重新排序。由于计算成本高,在初始检索后运用基于机器学习模型的重新排序,将结果集缩减到一小部分有希望的候选对象。
结论借助上述组件,我们构建了一个智能搜索管道,它集成了以下部分:
全文搜索,面向精确的关键字匹配向量搜索,面向语义匹配结果融合,使用机器学习结合结果和重新排序我们通过使用存储所有数据的单一数据库系统来做到这一点。由于避免了与单独的搜索引擎或数据库集成,我们就不需要拥有多个技术堆栈,并降低了系统的复杂性。
原文标题:Hybrid Search Using Postgres DB,作者:Suraj Dharmapuram
相关文章:
源码下载服务器租用益华科技香港云服务器企商汇IT资讯网源码库IT技术网亿华云编程之道思维库亿华互联IT资讯网亿华智造益强数据堂益强智囊团益华科技亿华云计算运维纵横益强IT技术网科技前瞻亿华科技云站无忧益强前沿资讯益华IT技术论坛益强编程堂益强智未来极客编程益华科技亿华智慧云亿华云创站工坊益强资讯优选汇智坊亿华灵动技术快报极客码头益强科技益强科技智能时代多维IT资讯全栈开发码上建站益强编程舍
0.1312s , 11781.7578125 kb
Copyright © 2025 Powered by 如何使用Postgres DB实现混合搜索,汇智坊 滇ICP备2023006006号-2