AI代码开发宝库系列:FAISS向量数据库

FAISS向量数据库从入门到精通:让你的文本检索快如闪电!

大家好,我是你们的AI技术博主!今天我们来聊聊一个能让文本检索速度飞起来的神器------FAISS!如果你还在为海量文档检索慢而烦恼,那这篇文章绝对能让你眼前一亮!

基于FAISS构建法律文档向量数据库https://blog.csdn.net/chenchihwen/article/details/149835193?spm=1001.2101.3001.10796

什么是FAISS?为什么你需要它?

FAISS是Facebook AI团队开源的一个超高效的向量搜索引擎,专门用于快速相似性搜索和聚类密集向量。简单来说,它能帮你解决这样一个问题:

当你有成千上万个文档,用户问一个问题时,如何在毫秒级时间内找出最相关的几个文档?

传统关键词搜索已经不够用了!我们需要的是语义级别的理解,而这就需要用到Embedding技术和向量数据库。

核心概念:从文本到向量

想象一下,任何一段文本都可以变成一个多维空间中的点(向量),语义相近的文本在这个空间中距离很近,语义不同的文本距离较远。这就是Embedding的魅力!

复制代码
# 示例:将文本转换为向量
completion = client.embeddings.create(
    model="text-embedding-v4",
    input="迪士尼乐园的门票一经售出,原则上不予退换",
    dimensions=1024,  # 1024维向量
    encoding_format="float"
)
vector = completion.data[0].embedding  # 这就是一个1024维的向量!

FAISS实战:三步搞定向量检索

废话不多说,直接上代码!让你3分钟掌握FAISS的核心用法:

第一步:准备数据和向量

复制代码
import numpy as np
import faiss
​
# 准备你的文档数据
documents = [
    {
        "id": "doc1",
        "text": "迪士尼乐园的门票一经售出,原则上不予退换。",
        "metadata": {"category": "退票政策"}
    },
    {
        "id": "doc2",
        "text": "购买“奇妙年卡”的用户,可以享受一年内多次入园的特权。",
        "metadata": {"category": "会员权益"}
    }
]
​
# 为每个文档生成向量(这里简化处理)
vectors_list = []  # 存储向量
metadata_store = []  # 存储元数据
vector_ids = []  # 存储ID
​
for i, doc in enumerate(documents):
    # 实际应用中这里调用API生成向量
    vector = get_embedding(doc["text"])  # 假设这个函数能生成向量
    vectors_list.append(vector)
    metadata_store.append(doc)
    vector_ids.append(i)

第二步:构建FAISS索引

复制代码
# 转换为NumPy数组
vectors_np = np.array(vectors_list).astype('float32')
vector_ids_np = np.array(vector_ids)
​
# 创建FAISS索引(关键步骤!)
dimension = 1024  # 向量维度
index_flat_l2 = faiss.IndexFlatL2(dimension)  # L2距离索引
index = faiss.IndexIDMap(index_flat_l2)  # 映射自定义ID
​
# 添加向量到索引中
index.add_with_ids(vectors_np, vector_ids_np)
print(f"FAISS索引创建成功,共包含 {index.ntotal} 个向量。")

第三步:执行相似性搜索

复制代码
# 用户查询
query_text = "我想了解一下迪士尼门票的退款流程"
​
# 为查询生成向量
query_vector = np.array([get_embedding(query_text)]).astype('float32')
​
# 在FAISS中搜索最相似的3个向量
k = 3
distances, retrieved_ids = index.search(query_vector, k)
​
# 展示结果
for i in range(k):
    doc_id = retrieved_ids[0][i]
    if doc_id != -1:  # 检查是否找到匹配项
        retrieved_doc = metadata_store[doc_id]
        print(f"排名 {i+1} (距离: {distances[0][i]:.4f})")
        print(f"内容: {retrieved_doc['text']}")

实际应用:ChatPDF文档问答系统

来看一个更实际的例子------基于PDF文档的智能问答系统:

复制代码
from PyPDF2 import PdfReader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import FAISS
​
# 1. 读取PDF文件
pdf_reader = PdfReader('your_document.pdf')
text = ""
for page in pdf_reader.pages:
    text += page.extract_text()
​
# 2. 分割文本(因为向量模型通常有长度限制)
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,
    chunk_overlap=200
)
chunks = text_splitter.split_text(text)
​
# 3. 创建向量数据库
embeddings = OpenAIEmbeddings()
knowledgeBase = FAISS.from_texts(chunks, embeddings)
​
# 4. 查询相似内容
query = "文档中关于退款的规定是什么?"
docs = knowledgeBase.similarity_search(query)
​
# 5. 结合大语言模型生成答案
# (这部分涉及LLM调用,此处省略详细代码)

实际应用:ChatPDF文档问答系统

来看一个更实际的例子------基于PDF文档的智能问答系统:

复制代码
from PyPDF2 import PdfReader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import FAISS
from typing import List, Tuple

def extract_text_with_page_numbers(pdf) -> Tuple[str, List[int]]:
    """
    从PDF中提取文本并记录每行文本对应的页码
    
    参数:
        pdf: PDF文件对象
    
    返回:
        text: 提取的文本内容
        page_numbers: 每行文本对应的页码列表
    """
    text = ""
    page_numbers = []

    for page_number, page in enumerate(pdf.pages, start=1):
        extracted_text = page.extract_text()
        if extracted_text:
            text += extracted_text
            # 记录每个文本块对应的页码
            page_numbers.extend([page_number] * len(extracted_text.split("\n")))
        else:
            print(f"警告: 第 {page_number} 页未找到文本内容。")

    return text, page_numbers

def process_text_with_splitter(text: str, page_numbers: List[int]) -> FAISS:
    """
    处理文本并创建向量存储
    
    参数:
        text: 提取的文本内容
        page_numbers: 每行文本对应的页码列表
    
    返回:
        knowledgeBase: 基于FAISS的向量存储对象
    """
    # 创建文本分割器,用于将长文本分割成小块
    text_splitter = RecursiveCharacterTextSplitter(
        separators=["\n\n", "\n", ".", " ", ""],
        chunk_size=1000,      # 每个文本块最大1000个字符
        chunk_overlap=200,    # 文本块之间重叠200个字符
        length_function=len,
    )

    # 分割文本
    chunks = text_splitter.split_text(text)
    print(f"文本被分割成 {len(chunks)} 个块。")
        
    # 创建嵌入模型
    embeddings = OpenAIEmbeddings()
    # 从文本块创建知识库
    knowledgeBase = FAISS.from_texts(chunks, embeddings)
    print("已从文本块创建知识库。")
    
    # 存储每个文本块对应的页码信息(重要:用于结果溯源)
    knowledgeBase.page_info = {chunk: page_numbers[i] for i, chunk in enumerate(chunks)}

    return knowledgeBase

# 读取PDF文件
pdf_reader = PdfReader('./浦发上海浦东发展银行西安分行个金客户经理考核办法.pdf')
# 提取文本和页码信息
text, page_numbers = extract_text_with_page_numbers(pdf_reader)
print(f"提取的文本长度: {len(text)} 个字符。")
    
# 处理文本并创建知识库
knowledgeBase = process_text_with_splitter(text, page_numbers)

# 设置查询问题
query = "客户经理每年评聘申报时间是怎样的?"
if query:
    # 执行相似度搜索,找到与查询相关的文档
    docs = knowledgeBase.similarity_search(query)
    
    # 显示查询结果及来源页码
    print("查询结果:")
    unique_pages = set()
    
    for i, doc in enumerate(docs):
        print(f"\n--- 结果 {i+1} ---")
        print(f"内容: {doc.page_content}")
        
        # 显示来源页码
        source_page = knowledgeBase.page_info.get(doc.page_content.strip(), "未知")
        if source_page not in unique_pages:
            unique_pages.add(source_page)
            print(f"来源页码: {source_page}")

性能对比:快得惊人!

让我给你看看FAISS到底有多快:

  • 传统数据库全文检索:秒级响应

  • FAISS向量检索:毫秒级响应

  • 处理百万级向量:依然保持毫秒级响应

这性能提升,简直是从马车升级到了火箭!

实战技巧和注意事项

1. 向量维度选择

复制代码
# 不同模型有不同的维度
dimensions = 1024  # text-embedding-v4
dimensions = 1536  # OpenAI ada-002
dimensions = 768   # BERT-base

2. 索引类型选择

复制代码
# 精确搜索(适合小数据集)
index = faiss.IndexFlatL2(dimension)
​
# 近似搜索(适合大数据集,更快但稍有精度损失)
index = faiss.IndexIVFFlat(quantizer, dimension, nlist)

3. 元数据管理

复制代码
# 向量和元数据的对应关系是关键
metadata_store = []  # 用列表索引与向量ID对应
# 或者用字典存储
metadata_dict = {doc_id: doc_metadata}

应用场景大盘点

  1. 智能客服系统:快速匹配用户问题与知识库中的答案

  2. 文档问答系统:像ChatPDF一样实现PDF智能问答

  3. 推荐系统:根据用户兴趣向量推荐相关内容

  4. 代码搜索:在代码库中快速找到相关函数或模块

  5. 法律咨询:快速检索相关法条(正如CSDN博客中提到的法律文档案例)

总结

FAISS真的是一个改变游戏规则的工具!它让原本复杂的向量检索变得简单高效。掌握了FAISS,你就拥有了构建各种AI应用的利器!

记住这几个关键点:

  • 文本 → 向量 → FAISS索引 → 快速检索

  • 向量维度要匹配你的Embedding模型

  • 元数据管理是连接向量和原始信息的桥梁

  • 根据数据规模选择合适的索引类型

赶紧动手试试吧!相信我,一旦你体验过FAISS的速度,就再也回不去了!

如果你觉得这篇文章对你有帮助,别忘了点赞收藏关注哦!后续还会带来更多AI实战干货,让我们一起在AI的世界里乘风破浪!

相关推荐
好学且牛逼的马3 小时前
Spring Task 核心解析:从原理到源码的简洁逻辑链
1024程序员节
java_logo3 小时前
Docker 部署 WordPress 全流程
运维·docker·容器·word·php·1024程序员节
张登杰踩3 小时前
工业产品表面缺陷检测方法综述:从传统视觉到深度学习
人工智能·深度学习
web打印社区3 小时前
使用React如何静默打印页面:完整的前端打印解决方案
前端·javascript·vue.js·react.js·pdf·1024程序员节
叶凡要飞3 小时前
RTX5060Ti安装cuda加速的openCV
1024程序员节
MATLAB代码顾问3 小时前
MATLAB 实现图像边缘检测与轮廓提取(Canny、Sobel、Prewitt 算子对比)
1024程序员节
DeeplyMind3 小时前
AMD rocr-libhsakmt分析系列3-4:svm-reserve模式实现分析
linux·驱动开发·1024程序员节·amdgpu·kfd·rocr
神秘的土鸡3 小时前
从数据仓库到数据中台再到数据飞轮:我的数据技术成长之路
java·服务器·aigc·数据库架构·1024程序员节
烦恼归林4 小时前
学习经验分享篇(4)——硕士入门电机控制的经历经验分享
经验分享·电机·电力电子·1024程序员节·电机控制·永磁同步电机·simulink仿真