Skip to main content

BigtableByteStore

本指南介绍如何将 Google Cloud Bigtable 用作键值存储。 Bigtable 是一种键值和宽列存储,非常适合快速访问结构化、半结构化或非结构化数据。 Open In Colab

概述

BigtableByteStore 使用 Google Cloud Bigtable 作为键值存储的后端,支持对键值对进行同步和异步的设置、获取及删除操作。

集成详情

本地支持JS 支持包下载量最新版本
BigtableByteStorelangchain-google-bigtablePyPI - DownloadsPyPI - Version

配置

前提条件

开始之前,你需要一个拥有活跃 Bigtable 实例和表的 Google Cloud 项目。

安装

集成位于 langchain-google-bigtable 包中。以下命令同时安装 langchain-google-vertexai,用于嵌入缓存示例。
pip install -qU langchain-google-bigtable langchain-google-vertexai

设置 Google Cloud 项目

设置你的 Google Cloud 项目,以便在此 notebook 中使用其资源。 如果不知道项目 ID,可以运行 gcloud config list,或参阅支持页面:查找项目 ID
# @markdown Please fill in your project, instance, and table details.
PROJECT_ID = "your-gcp-project-id"  # @param {type:"string"}
INSTANCE_ID = "your-instance-id"  # @param {type:"string"}
TABLE_ID = "your-table-id"  # @param {type:"string"}

!gcloud config set project {PROJECT_ID}

身份验证

向 Google Cloud 进行身份验证以访问项目资源。
  • Colab 中,使用以下单元格。
  • Vertex AI Workbench 中,请参阅配置说明
from google.colab import auth

auth.authenticate_user()

实例化

使用 BigtableByteStore 时,首先确保表存在,然后初始化 BigtableEngine 来管理连接。
from langchain_google_bigtable import (
    BigtableByteStore,
    BigtableEngine,
    init_key_value_store_table,
)

# Ensure the table and column family exist.
init_key_value_store_table(
    project_id=PROJECT_ID,
    instance_id=INSTANCE_ID,
    table_id=TABLE_ID,
)

BigtableEngine

BigtableEngine 对象负责处理存储的执行上下文,尤其是异步操作。建议初始化单个引擎并在多个存储间复用,以获得更好的性能。
# Initialize the engine to manage async operations.
engine = await BigtableEngine.async_initialize(
    project_id=PROJECT_ID, instance_id=INSTANCE_ID
)

BigtableByteStore

这是与键值存储交互的主要类,提供设置、获取和删除数据的方法。
# Initialize the store.
store = await BigtableByteStore.create(engine=engine, table_id=TABLE_ID)

使用方法

存储同时支持同步(msetmget)和异步(amsetamget)方法。本指南使用异步版本。

设置

使用 amset 将键值对保存到存储中。
kv_pairs = [
    ("key1", b"value1"),
    ("key2", b"value2"),
    ("key3", b"value3"),
]

await store.amset(kv_pairs)

获取

使用 amget 获取值。若键不存在,该键对应位置返回 None
retrieved_vals = await store.amget(["key1", "key2", "nonexistent_key"])
print(retrieved_vals)

删除

使用 amdelete 从存储中移除键。
await store.amdelete(["key3"])

# Verifying the key was deleted
await store.amget(["key1", "key3"])

遍历键

使用 ayield_keys 遍历所有键或具有特定前缀的键。
all_keys = [key async for key in store.ayield_keys()]
print(f"All keys: {all_keys}")

prefixed_keys = [key async for key in store.ayield_keys(prefix="key1")]
print(f"Prefixed keys: {prefixed_keys}")

高级用法:嵌入缓存

键值存储的一个常见用途是缓存耗费资源的操作(例如计算文本嵌入),从而节省时间和成本。
from langchain.embeddings import CacheBackedEmbeddings
from langchain_google_vertexai.embeddings import VertexAIEmbeddings

underlying_embeddings = VertexAIEmbeddings(
    project=PROJECT_ID, model_name="textembedding-gecko@003"
)

# Use a namespace to avoid key collisions with other data.
cached_embedder = CacheBackedEmbeddings.from_bytes_store(
    underlying_embeddings, store, namespace="text-embeddings"
)
print("First call (computes and caches embedding):")
%time embedding_result_1 = await cached_embedder.aembed_query("Hello, world!")
print("\nSecond call (retrieves from cache):")
%time embedding_result_2 = await cached_embedder.aembed_query("Hello, world!")

作为简单的文档检索器

本节展示如何使用 Bigtable 存储创建一个简单的检索器,它充当文档持久层,获取与查询前缀匹配的文档。
from langchain_core.retrievers import BaseRetriever
from langchain_core.documents import Document
from langchain_core.callbacks import CallbackManagerForRetrieverRun
from typing import List, Optional, Any, Union
import json


class SimpleKVStoreRetriever(BaseRetriever):
    """A simple retriever that retrieves documents based on a prefix match in the key-value store."""

    store: BigtableByteStore
    documents: List[Union[Document, str]]
    k: int

    def set_up_store(self):
        kv_pairs_to_set = []
        for i, doc in enumerate(self.documents):
            if isinstance(doc, str):
                doc = Document(page_content=doc)
            if not doc.id:
                doc.id = str(i)
            value = (
                "Page Content\n"
                + doc.page_content
                + "\nMetadata"
                + json.dumps(doc.metadata)
            )
            kv_pairs_to_set.append((doc.id, value.encode("utf-8")))
        self.store.mset(kv_pairs_to_set)

    async def _aget_relevant_documents(
        self,
        query: str,
        *,
        run_manager: Optional[CallbackManagerForRetrieverRun] = None,
    ) -> List[Document]:
        keys = [key async for key in self.store.ayield_keys(prefix=query)][: self.k]
        documents_retrieved = []
        async for document in await self.store.amget(keys):
            if document:
                document_str = document.decode("utf-8")
                page_content = document_str.split("Content\n")[1].split("\nMetadata")[0]
                metadata = json.loads(document_str.split("\nMetadata")[1])
                documents_retrieved.append(
                    Document(page_content=page_content, metadata=metadata)
                )
        return documents_retrieved

    def _get_relevant_documents(
        self,
        query: str,
        *,
        run_manager: Optional[CallbackManagerForRetrieverRun] = None,
    ) -> list[Document]:
        keys = [key for key in self.store.yield_keys(prefix=query)][: self.k]
        documents_retrieved = []
        for document in self.store.mget(keys):
            if document:
                document_str = document.decode("utf-8")
                page_content = document_str.split("Content\n")[1].split("\nMetadata")[0]
                metadata = json.loads(document_str.split("\nMetadata")[1])
                documents_retrieved.append(
                    Document(page_content=page_content, metadata=metadata)
                )
        return documents_retrieved
documents = [
    Document(
        page_content="Goldfish are popular pets for beginners, requiring relatively simple care.",
        metadata={"type": "fish", "trait": "low maintenance"},
        id="fish#Goldfish",
    ),
    Document(
        page_content="Cats are independent pets that often enjoy their own space.",
        metadata={"type": "cat", "trait": "independence"},
        id="mammals#Cats",
    ),
    Document(
        page_content="Rabbits are social animals that need plenty of space to hop around.",
        metadata={"type": "rabbit", "trait": "social"},
        id="mammals#Rabbits",
    ),
]
retriever_store = BigtableByteStore.create_sync(
    engine=engine, instance_id=INSTANCE_ID, table_id=TABLE_ID
)

KVDocumentRetriever = SimpleKVStoreRetriever(
    store=retriever_store, documents=documents, k=2
)

KVDocumentRetriever.set_up_store()
KVDocumentRetriever.invoke("fish")
KVDocumentRetriever.invoke("mammals")

API 参考

有关 BigtableByteStore 类的完整详情,请参阅 GitHub 上的源代码。