1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MeMemo: ブラウザで動作するベクトル検索ライブラリの紹介

Posted at

MeMemoは、ブラウザ上でベクトル検索とRetrieval Augmented Generation (RAG)を実現するJavaScriptライブラリです。ブラウザ環境でHNSW(Hierarchical Navigable Small World)アルゴリズムを実装し、クライアントサイドで効率的なベクトル検索を可能にします。

特徴

  1. ブラウザネイティブ

    • IndexedDBを使用したデータの永続化
    • Web Workersによる並列処理
    • クライアントサイドで完結
  2. 高速な検索

    • HNSWアルゴリズムによる近似最近傍探索
    • インデックスによる効率的な検索
    • ブラウザの性能を最大限活用
  3. プライバシー重視

    • データはすべてクライアントサイドで処理
    • サーバーへの送信不要
    • オフライン動作可能

基本的な使い方

1. インストール

npmを使用してMeMemoをインストールします:

npm install mememo

2. インデックスの作成

HNSWインデックスを初期化します:

import { HNSW } from 'mememo';

const index = new HNSW({ 
  // コサイン類似度を使用
  distanceFunction: 'cosine-normalized',
  
  // 各ノードの最大接続数(5-48の範囲を推奨)
  m: 16,
  
  // ブラウザのIndexedDBを使用してデータを永続化
  useIndexedDB: true
});

3. ドキュメントの登録

テキストをチャンクに分割し、ベクトル化してインデックスに登録します:

// テキストをチャンクに分割
function splitIntoChunks(text: string, maxChunkSize = 512) {
  const sentences = text.match(/[^.!?]+[.!?]+/g) || [];
  let chunks = [];
  let currentChunk = '';

  for (const sentence of sentences) {
    if (currentChunk.length + sentence.length > maxChunkSize) {
      chunks.push(currentChunk.trim());
      currentChunk = sentence;
    } else {
      currentChunk += ' ' + sentence;
    }
  }
  if (currentChunk) chunks.push(currentChunk.trim());
  return chunks;
}

// ドキュメントを登録
async function indexDocument(text: string) {
  // テキストをチャンクに分割
  const chunks = splitIntoChunks(text);
  
  // チャンクをベクトル化(例:GTE-Smallモデルを使用)
  const vectors = await model.embed(chunks);
  
  // キーを生成
  const keys = chunks.map((_, i) => `chunk_${i}`);
  
  // インデックスに登録
  await index.bulkInsert(keys, vectors);
  
  return keys;
}

4. 検索の実行

登録したドキュメントから類似コンテンツを検索します:

// 基本的な検索
async function searchSimilar(query: string, k: number = 5) {
  // クエリをベクトル化
  const queryVector = await model.embed(query);
  
  // k個の類似ドキュメントを検索
  const { keys, distances } = await index.query(queryVector, k);
  
  // 結果を類似度スコアと共に返す
  return keys.map((key, i) => ({
    key,
    chunk: chunks[key],  // オリジナルのテキストチャンク
    similarity: 1 - distances[i]  // 距離を類似度スコアに変換
  }));
}

// メタデータを含む検索の実装例
interface DocumentChunk {
  id: string;
  text: string;
  metadata: {
    title: string;
    source: string;
    timestamp: string;
  };
}

const documentStore = new Map<string, DocumentChunk>();

async function indexDocumentWithMetadata(
  text: string,
  metadata: { title: string; source: string }
) {
  const chunks = splitIntoChunks(text);
  const vectors = await model.embed(chunks);
  
  // チャンク情報をストアに保存
  const chunkDocuments = chunks.map((chunk, i) => ({
    id: `doc_${metadata.title}_${i}`,
    text: chunk,
    metadata: {
      ...metadata,
      timestamp: new Date().toISOString()
    }
  }));
  
  // メタデータを含むチャンク情報を保存
  for (const doc of chunkDocuments) {
    documentStore.set(doc.id, doc);
  }
  
  // ベクトルインデックスに登録
  await index.bulkInsert(
    chunkDocuments.map(d => d.id),
    vectors
  );
  
  return chunkDocuments.map(d => d.id);
}

5. 使用例

// ドキュメントの登録と検索
async function example() {
  // ドキュメントを登録
  await indexDocumentWithMetadata(
    "長いテキストドキュメント...",
    {
      title: "サンプル文書",
      source: "ウェブサイト"
    }
  );
  
  // 検索を実行
  const results = await searchWithMetadata("検索クエリ");
  
  // 結果を表示
  for (const result of results) {
    console.log(`スコア: ${result.similarity}`);
    console.log(`タイトル: ${result.metadata.title}`);
    console.log(`ソース: ${result.metadata.source}`);
    console.log(`テキスト: ${result.text}`);
    console.log('---');
  }
}

実装の注意点

  1. チャンクサイズ

    • 適切なサイズ(300-1000トークン程度)に分割
    • 文脈を保持できる大きさを維持
  2. ベクトル化

    • 一貫した埋め込みモデルを使用
    • 正規化されたベクトルを使用(cosine-normalizedの場合)
  3. 検索結果の処理

    • 類似度スコアに基づくフィルタリング
    • メタデータを活用した結果のグループ化
    • 適切なスコアのしきい値設定

参考URL

デモサイトでは、以下の3つのユースケースを試すことができます:

  • ML Paper Reviewer: 機械学習論文のレビュー支援
  • Prompt Enhancer: 生成AIのプロンプト最適化
  • Responsible AI Assistant: AIの倫理と安全性に関する知識提供

まとめ

MeMemoを使用することで、ブラウザ上で効率的なベクトル検索を実現できます。すべての処理がクライアントサイドで完結するため、プライバシーを保ちながらRAGシステムを構築できます。

基本的な実装に加えて、メタデータの活用や検索結果の後処理など、実用的な機能を追加することで、より高度な検索システムを構築することが可能です。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?