分散データの統合とベクトル検索 — 複数のデータソースを1つに集約する設計

マニュアル、対応履歴、見積データなど、複数のデータソースを1つのデータベースに統合し、横断検索を実現する仕組み

データ統合Embeddingチャンク横断検索OpenAIベクトルDB
読了時間: 11分

はじめに

社内の情報は、さまざまな場所に分散しています。マニュアルは社内Wiki、過去の対応履歴はスプレッドシート、商品情報は別のシステム——これらを横断して検索できないことが、業務効率を下げる大きな原因になっています。

この記事では、複数のデータソースを1つのデータベースに統合し、「1回の検索で全データを横断できる」仕組みを構築した方法を解説します。

分散データの課題

情報が見つからない問題

対応マニュアル
保存場所社内Wiki
検索方法Wiki内検索
過去の対応履歴
保存場所スプレッドシート
検索方法Ctrl+F で手動検索
見積データ
保存場所別のスプレッドシート
検索方法シート内検索
商品マスタ
保存場所また別のスプレッドシート
検索方法品番で検索

それぞれのツールで検索する必要があり、「どこに書いてあるか分からない」「検索しても見つからない」という問題が発生します。

統合のメリット

これらを1つのデータベースに統合すると、以下のメリットがあります。

  • 1回の検索で全データを横断:質問に関連する情報を、ソースを問わず取得
  • 意味による検索:「返金」で検索しても「払い戻し」「キャンセル」がヒット
  • 参照元の明示:どのデータソースから取得したかを表示

データソースの統合設計

統一スキーマの設計

複数のデータソースを統合するには、**共通のデータ構造(スキーマ)**が必要です。

content
説明検索対象のテキスト本文
「返金のご依頼を承りました...」
source_type
説明データの種類
faq / ticket / estimate / product
source_id
説明元データの識別子
FAQ-001, TICKET-12345
metadata
説明追加情報(JSON)
カテゴリ、日付、タグなど
embedding
説明ベクトル化されたデータ
[0.12, -0.34, ...]
content_hash
説明変更検知用のハッシュ
a1b2c3d4...

データソースごとの変換

各データソースは形式が異なるため、統一スキーマへの変換処理が必要です。

データ統合の流れ
社内Wiki

Markdown形式

スプレッドシート

行ごとのデータ

PDF

文書ファイル

変換処理
統一スキーマ

content + source_type + metadata + embedding

保存
ベクトルDB(Neon + pgvector)

横断検索が可能に

各データソースの取り込み

FAQマニュアル(JSON形式)

手動で整備した対応マニュアルは、JSON形式で管理しています。

{
  "id": "FAQ-001",
  "question": "返金の手続きはどうすればいいですか?",
  "answer": "返金のご依頼を承りました...",
  "category": "決済",
  "tags": ["返金", "キャンセル"]
}

これを統一スキーマに変換する際、質問と回答を結合してcontentとします。

対応履歴(スプレッドシート)

過去の対応履歴は、スプレッドシートに蓄積されています。

2024/01/15
問い合わせ内容注文した商品が届かない
対応内容配送状況を確認し...
結果解決
2024/01/16
問い合わせ内容返品したい
対応内容返品条件を説明し...
結果対応中

これらを1行ずつ取り込み、問い合わせ内容と対応内容を結合してcontentとします。

見積データ・商品マスタ

見積データや商品マスタは、検索時に補足情報として使われます。

「この修理の見積もりはいくらくらい?」
→ 見積データから関連情報を取得
→ 「〇〇の修理は△△円〜□□円が目安です」と回答

Embedding処理の実装

OpenAI Embedding APIの利用

テキストをベクトルに変換するには、OpenAIのEmbedding APIを使用します。

text-embedding-3-small
次元数1536
特徴コスト効率が良い、十分な精度
text-embedding-3-large
次元数3072
特徴より高精度だがコストも高い

このプロジェクトでは、コストと精度のバランスからtext-embedding-3-smallを採用しています。

バッチ処理

数千件のデータを処理する場合、1件ずつAPIを呼ぶと時間がかかります。そこで、バッチ処理で効率化しています。

Embedding処理の流れ
データ取得

各データソースからデータを読み込み

ハッシュ比較

前回と変更があるかチェック

バッチ変換

変更があるものだけをまとめてEmbedding

DB保存

ベクトルとメタデータをDBに保存

横断検索の実装

ソースタイプによるフィルタリング

必要に応じて、特定のデータソースのみを検索することも可能です。

-- FAQのみを検索
WHERE source_type = 'faq'

-- FAQと対応履歴を検索
WHERE source_type IN ('faq', 'ticket')

検索結果の活用

検索結果は、AIへの入力として使われます。

【検索結果】
1. [FAQ] 返金の手続きについて
   返金のご依頼は、以下の手順でお受けしています...

2. [対応履歴] 2024/01/10の対応事例
   同様のケースでは、〇〇の方法で対応しました...

3. [見積] △△の料金表
   この作業の目安価格は□□円です...

AIは、これらの情報を元に回答を生成します。

なぜ同じテーブルに入れるのか

別テーブル vs 同じテーブル

データソースごとに別テーブルを作る方法もありますが、このプロジェクトでは同じテーブルに統合しました。

別テーブル
メリットデータ構造を柔軟に設計可能
デメリット横断検索が複雑になる
同じテーブル
メリット1クエリで全データを検索可能
デメリットスキーマの統一が必要

統合の利点

同じテーブルに入れることで、以下の利点があります。

  1. 質問の意図を推測しなくていい

    • 「マニュアルを見たいのか」「過去事例を見たいのか」をユーザーが指定しなくていい
    • 質問内容に応じて、最適な情報が自動で選ばれる
  2. 検索ロジックがシンプル

    • 1回のクエリで完結
    • 複数テーブルをUNIONする必要がない
  3. 類似度の比較が正確

    • 同じEmbeddingモデルで変換されているため、類似度が比較可能

データ品質の確保

重複データの排除

同じ内容が複数回取り込まれないよう、source_idによる重複チェックを行います。

既存データがある場合:
- content_hashが同じ → スキップ
- content_hashが異なる → 更新

欠損データの処理

必須フィールドが欠けているデータは、取り込み時にスキップまたは補完します。

content
欠損時の処理空の場合はスキップ(検索対象にならない)
source_type
欠損時の処理必須(データソースの識別に必要)
metadata
欠損時の処理空でも可(オプション情報)

まとめ

分散データを統合することで、以下を実現しました。

  1. 1回の検索で全データを横断:質問に最適な情報がソースを問わず見つかる
  2. 意味ベースの検索:キーワードの揺れに対応
  3. 参照元の明示:どのデータソースから取得したかが分かる

データ統合は初期構築に手間がかかりますが、一度仕組みを作れば、新しいデータソースの追加も容易になります。

関連記事