我如何使用 CocoIndex 构建语义搜索引擎

发布: (2025年12月3日 GMT+8 06:04)
5 min read
原文: Dev.to

Source: Dev.to

介绍

在本教程中,我将向你展示如何使用 CocoIndex——一个用于创建强大搜索体验的开源 Python 库——构建语义搜索引擎。如果你曾想构建一个能够理解上下文和含义(而不仅仅是精确关键词匹配)的搜索功能,那么本文适合你!

什么是 CocoIndex?

CocoIndex 是一个轻量级的语义搜索库,能够轻松地对文档进行向量嵌入并进行搜索。与传统的基于关键词的搜索不同,语义搜索能够理解查询背后的意义,使用户即使使用不同的词语也能找到相关结果。

为什么选择 CocoIndex

我需要一个满足以下条件的搜索解决方案:

  • 易于集成 – 无需复杂的设置或基础设施
  • 高速 – 快速的索引和搜索性能
  • 语义化 – 理解上下文,而不仅仅是关键词
  • 开源 – 免费使用且可自行修改

CocoIndex 完全满足了这些要求!

入门

首先,安装 CocoIndex:

pip install cocoindex

构建搜索引擎

1. 初始化 CocoIndex

from cocoindex import CocoIndex

2. 添加文档

@cocoindex.flow_def(name="TextEmbedding")
def text_embedding_flow(flow_builder: cocoindex.FlowBuilder, data_scope: cocoindex.DataScope):
    """
    Define an example flow that embeds text into a vector database.
    """
    data_scope["documents"] = flow_builder.add_source(
        cocoindex.sources.LocalFile(path="markdown_files")
    )

    doc_embeddings = data_scope.add_collector()

索引文档

处理每个文档

with data_scope["documents"].row() as doc:
    doc["chunks"] = doc["content"].transform(
        cocoindex.functions.SplitRecursively(),
        language="markdown",
        chunk_size=2000,
        chunk_overlap=500,
    )

嵌入

with doc["chunks"].row() as chunk:
    chunk["embedding"] = chunk["text"].transform(
        cocoindex.functions.SentenceTransformerEmbed(
            model="sentence-transformers/all-MiniLM-L6-v2"
        )
    )
    doc_embeddings.collect(
        filename=doc["filename"],
        location=chunk["location"],
        text=chunk["text"],
        embedding=chunk["embedding"],
    )

导出

doc_embeddings.export(
    "doc_embeddings",
    cocoindex.storages.Postgres(),
    primary_key_fields=["filename", "location"],
    vector_indexes=[
        cocoindex.VectorIndexDef(
            field_name="embedding",
            metric=cocoindex.VectorSimilarityMetric.COSINE_SIMILARITY,
        )
    ],
)

3. 执行语义搜索

def search(pool: ConnectionPool, query: str, top_k: int = 5):
    table_name = cocoindex.utils.get_target_storage_default_name(
        text_embedding_flow, "doc_embeddings"
    )
    query_vector = text_to_embedding.eval(query)

    with pool.connection() as conn:
        with conn.cursor() as cur:
            cur.execute(
                f"""
                SELECT filename, text, embedding  %s::vector AS distance
                FROM {table_name}
                ORDER BY distance
                LIMIT %s
                """,
                (query_vector, top_k),
            )
            return [
                {"filename": row[0], "text": row[1], "score": 1.0 - row[2]}
                for row in cur.fetchall()
            ]

我实现的关键特性

快速索引

CocoIndex 使用高效的向量存储,使得对成千上万的文档进行索引既快速又轻松。

语义理解

搜索能够理解“teaching computers”与“machine learning”之间的关联,即使没有完全匹配的关键词。

可定制的嵌入模型

你可以根据具体需求和精度要求选择不同的嵌入模型。

实际案例

我为自己的项目构建了一个包含 500 多个 markdown 文件的文档搜索。使用 CocoIndex:

  • 索引耗时不到 30 秒
  • 搜索响应时间平均 50 ms
  • 用户即使使用模糊查询也能找到相关文档

性能优化技巧

  • 批量索引 – 一次添加多个文档以提升性能
  • 选择合适的嵌入模型 – 在精度和速度之间取得平衡
  • 缓存常用结果 – 将常见查询的结果存储起来,实现即时响应

我遇到的挑战

挑战 1:选择嵌入维度

维度越高精度越好,但性能会下降。我最终选择了 384 维作为折中方案。

挑战 2:处理大规模文档集合

对于超过 1 万篇文档的集合,我实现了分页和惰性加载。

结果

使用 CocoIndex 后:

  • 用户满意度显著提升
  • 实现时间仅 2 天,而其他方案需要数周

结论

CocoIndex 让构建语义搜索引擎变得异常简单。无论你是在构建文档站点、博客搜索还是产品目录,它都是一个轻量却功能强大的工具。该库维护活跃、文档完善,社区也很热心。强烈推荐在你的下一个搜索实现中尝试它!

资源

Back to Blog

相关文章

阅读更多 »