BedrockナレッジベースでAuroraを使ったハイブリッド検索サポート！日本語でもいけるの？？

少し前ですが、Bedrockナレッジベースで、Aurora(PostgreSQL)とMongoDB Atlasを使った場合のハイブリッド検索サポートが発表されました。

https://aws.amazon.com/jp/about-aws/whats-new/2025/04/amazon-bedrock-knowledge-bases-hybrid-search-aurora-postgresql-mongo-db-atlas-vector-stores/

ハイブリッド検索は、セマンティック検索とフルテキスト検索を組み合わせて実現します。
今回、Auroraのフルテキスト検索が、どういう仕組みで実現されているかと、日本語でも期待通りに動作するのかを検証しました。


## 検証した環境

今回検証した環境はAuroraではなく、Dockerで構築したPostgreSQL + pgvectorの環境です。もし実際のAuroraで動作が違ったらごめんなさい。

```dockerfile:Dockerfile.postgres
FROM pgvector/pgvector:pg16

# Expose the PostgreSQL port
EXPOSE 5432
```

```yaml:docker-compose.yml
version: '3.8'

services:
  postgres:
    build:
      context: .
      dockerfile: Dockerfile.postgres
    container_name: postgres_db
    restart: always
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: postgres
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080
    depends_on:
      - postgres

volumes:
  postgres_data:
```

## ハイブリッド検索用のテーブルを作成

Bedrockナレッジベースで利用できるテーブルの作成方法はこちらに記述があります。

https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.VectorDB.html

クエリを上から実行するだけです。

```sql
-- Enable the extension
CREATE EXTENSION IF NOT EXISTS vector;
SELECT extversion FROM pg_extension WHERE extname='vector';

-- Create a specific schema that Bedrock can use to query the data.
CREATE SCHEMA IF NOT EXISTS bedrock_integration;

-- Create a table in the bedrock_integration schema.
CREATE TABLE IF NOT EXISTS bedrock_integration.bedrock_kb (
    id UUID PRIMARY KEY,
    embedding VECTOR(1024),
    chunks TEXT,
    metadata JSON,
    custom_metadata JSONB
);

-- Create an index with the cosine operator which the bedrock can use to query the data.
CREATE INDEX ON bedrock_integration.bedrock_kb USING hnsw (embedding vector_cosine_ops);
-- We recommend you to set the value of ef_construction to 256 for pgvector 0.6.0 and higher version that use parallel index building.
CREATE INDEX ON bedrock_integration.bedrock_kb USING hnsw (embedding vector_cosine_ops) WITH (ef_construction=256);

-- Create an index which Bedrock can use to can use to query the text data.
CREATE INDEX ON bedrock_integration.bedrock_kb USING gin (to_tsvector('simple', chunks));

-- Create an index which Bedrock can use to can use to query the metadata.
CREATE INDEX ON bedrock_integration.bedrock_kb USING gin (custom_metadata);
```

ポイントは下から2個目のここです。TEXT型の`chunk`に全文検索で使用するインデックスを作成しています。

```sql
CREATE INDEX ON bedrock_integration.bedrock_kb USING gin (to_tsvector('simple', chunks));
```

https://www.postgresql.org/docs/current/textsearch-controls.html

これでテーブルが作成できました。

## 英語で検証

Bedrockの解説文全体を取り込みました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/50a950c0-fad5-486c-b2ce-798bd8e1657a.png)

```sql
INSERT INTO bedrock_integration.bedrock_kb (
    id,
    chunks
) VALUES (
    gen_random_uuid(),
    'Amazon Bedrock is a fully managed service that offers a choice of high-performing foundation models (FMs) from leading AI companies like AI21 Labs, Anthropic, Cohere, DeepSeek, Luma, Meta, Mistral AI, poolside (coming soon), Stability AI, TwelveLabs (coming soon), and Amazon through a single API, along with a broad set of capabilities you need to build generative AI applications with security, privacy, and responsible AI. Using Amazon Bedrock, you can easily experiment with and evaluate top FMs for your use case, privately customize them with your data using techniques such as fine-tuning and Retrieval Augmented Generation (RAG), and build agents that execute tasks using your enterprise systems and data sources. Since Amazon Bedrock is serverless, you don''t have to manage any infrastructure, and you can securely integrate and deploy generative AI capabilities into your applications using the AWS services you are already familiar with.'
);
```

全文検索を行う構文はこうなります。

```sql
SELECT *
FROM bedrock_integration.bedrock_kb
WHERE to_tsvector('simple', chunks) @@ to_tsquery('simple', 'bedrock');
```

- 「bedrock」または「knowledgebase」が含まれるものを検索する場合
    to_tsqueryの２つ目のパラメーターが`'bedrock | knowledgebase'`になります。
    →　上記のデータの場合に、検索にヒットしました

    ```sql
    SELECT *
    FROM bedrock_integration.bedrock_kb
    WHERE to_tsvector('simple', chunks) @@ to_tsquery('simple', 'bedrock | knowledgebase');
    ```
    

- 「bedrock」と「knowledgebase」が含まれるものを検索する場合
    to_tsqueryの２つ目のパラメーターが`'bedrock & knowledgebase'`になります。
    →　上記のデータの場合に、検索にヒットしませんでした（knowledgebaseはないので。）

    ```sql
    SELECT *
    FROM bedrock_integration.bedrock_kb
    WHERE to_tsvector('simple', chunks) @@ to_tsquery('simple', 'bedrock & knowledgebase');
    ```


`to_tsvector`と`to_tsquery`はそれぞれどんな値なのでしょうか？

- to_tsvector
    
    ```sql
    SELECT to_tsvector('simple', chunks) FROM bedrock_integration.bedrock_kb
    ```
    
    > 'a':4,10,44,49 'agents':103 'ai':21,32,37,59,66,135 'ai21':24 'along':47 'already':146 'amazon':1,42,68,115 'and':41,64,75,96,101,111,127,132 'anthropic':26 'any':125 'api':46 'applications':60,139 'are':145 'as':92 'augmented':98 'aws':142 'bedrock':2,69,116 'broad':50 'build':57,102 'can':71,129 'capabilities':53,136 'case':82 'choice':11 'cohere':27 'coming':34,39 'companies':22 'customize':84 'data':88,112 'deepseek':28 'deploy':133 'don':120 'easily':72 'enterprise':109 'evaluate':76 'execute':105 'experiment':73 'familiar':147 'fine':94 'fine-tuning':93 'fms':18,78 'for':79 'foundation':16 'from':19 'fully':5 'generation':99 'generative':58,134 'have':122 'high':14 'high-performing':13 'infrastructure':126 'integrate':131 'into':137 'is':3,117 'labs':25 'leading':20 'like':23 'luma':29 'manage':124 'managed':6 'meta':30 'mistral':31 'models':17 'need':55 'of':12,52 'offers':9 'performing':15 'poolside':33 'privacy':63 'privately':83 'rag':100 'responsible':65 'retrieval':97 'securely':130 'security':62 'serverless':118 'service':7 'services':143 'set':51 'since':114 'single':45 'soon':35,40 'sources':113 'stability':36 'such':91 'systems':110 't':121 'tasks':106 'techniques':90 'that':8,104 'the':141 'them':85 'through':43 'to':56,123 'top':77 'tuning':95 'twelvelabs':38 'use':81 'using':67,89,107,140 'with':48,61,74,86,148 'you':54,70,119,128,144 'your':80,87,108,138
    
    単語とその数値（位置かな？）の組み合わせの羅列でした。
    また、すべて小文字になっているところもポイントだと思います。
    
- to_tsquery

    ```sql
    SELECT to_tsquery('simple', 'Bedrock & Knowledgebase');
    ```
    
    > 'bedrock' & 'knowledgebase'
    
    指定した単語ごとに区切られています。こちらも小文字に変換されてますね。

    ```sql
    SELECT to_tsquery('simple', 'Bedrock | Knowledgebase');
    ```
    
    > 'bedrock' | 'knowledgebase'


ということで、おそらく元の文章を単語区切りかつ小文字にしたものがDBの中にインデックス登録されていて、検索クエリーを小文字にしたもので検索しているのでしょう。

:::note
意地悪（？）な検索ですが、上の文章の場合、`companies`（複数形）はインデックス化されていますが単数形の`company`は登録されていないので、次のSQLでは検索結果が0件になります。

```sql
SELECT *
FROM bedrock_integration.bedrock_kb
WHERE to_tsvector('simple', chunks) @@ to_tsquery('simple', 'company');
```
:::


## 日本語で検証

同じように日本語の説明文を取り込みました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/2c9ebfdf-de4d-427c-8681-72853c04de27.png)


```SQL
INSERT INTO bedrock_integration.bedrock_kb (
    id,
    chunks
) VALUES (
    gen_random_uuid(),
    'Amazon Bedrock は、単一の API を通じて AI21 Labs、Anthropic、Cohere、DeepSeek、Luma、Meta、Mistral AI、poolside (近日リリース予定)、Stability AI、および Amazon などの先駆的な AI 企業からの高性能な基盤モデル (FM) の幅広い選択肢を提供するフルマネージドサービスであり、セキュリティ、プライバシー、責任ある AI を備えた生成 AI アプリケーションを構築するために必要な一連の幅広い機能を提供します。Amazon Bedrock を使用すると、ユースケースに最適な FM を簡単に試して評価したり、微調整や検索拡張生成 (RAG) などの手法を使用してデータに合わせてカスタマイズしたり、エンタープライズシステムとデータソースを使用してタスクを実行するエージェントを構築したりできます。Amazon Bedrock はサーバーレスであるため、インフラストラクチャを管理する必要がありません。また、使い慣れた AWS サービスを使用して、生成 AI 機能をアプリケーションに安全に統合してデプロイできます。'
);
```

英語のときと同様、`to_tsvector`の値を確認してみましょう。

- to_tsvector
    
    ```sql
    SELECT to_tsvector('simple', chunks) FROM bedrock_integration.bedrock_kb
    ```

    > 'ai':15,19,23,30,32,53 'ai21':7 'amazon':1,21,34,44 'anthropic':9 'api':5 'aws':50 'bedrock':2,35,45 'cohere':10 'deepseek':11 'fm':25,38 'labs':8 'luma':12 'meta':13 'mistral':14 'poolside':16 'rag':41 'stability':18 'および':20 'などの先駆的な':22 'などの手法を使用してデータに合わせてカスタマイズしたり':42 'の幅広い選択肢を提供するフルマネージドサービスであり':26 'は':3 'はサーバーレスであるため':46 'また':48 'を使用すると':36 'を備えた生成':31 'を簡単に試して評価したり':39 'を通じて':6 'アプリケーションを構築するために必要な一連の幅広い機能を提供します':33 'インフラストラクチャを管理する必要がありません':47 'エンタープライズシステムとデータソースを使用してタスクを実行するエージェントを構築したりできます':43 'サービスを使用して':51 'セキュリティ':27 'プライバシー':28 'ユースケースに最適な':37 '企業からの高性能な基盤モデル':24 '使い慣れた':49 '単一の':4 '微調整や検索拡張生成':40 '機能をアプリケーションに安全に統合してデプロイできます':54 '生成':52 '責任ある':29 '近日リリース予定':17

    スペースや句読点で区切られるようです。

これはちょっと危険な香りがしますね。

- `セキュリティ`で検索
    ```sql
    SELECT *
    FROM bedrock_integration.bedrock_kb
    WHERE to_tsvector('simple', chunks) @@ to_tsquery('simple', 'セキュリティ');
    ```
    →検索結果あり（原文が「`...であり、セキュリティ、プライ...`」と前後に句読点あり）

- `サーバーレス`で検索

    ```sql
    SELECT *
    FROM bedrock_integration.bedrock_kb
    WHERE to_tsvector('simple', chunks) @@ to_tsquery('simple', 'サーバーレス');
    ```
    
    →検索結果なし（原文が「`...Bedrock はサーバーレスであるため...`」と前後に句読点なし）


うーん、**だめなんじゃない** ？


追加で、アルファベットの前後の空白を除いてみました。（先程の例は、機械翻訳あるあるで英単語の前後にもれなく空白が入ってました）

`また、使い慣れたAWSサービスを使用して、生成AI機能をアプリケーションに安全に統合してデプロイできます。`

- to_tsvector
    
    ```sql
    SELECT to_tsvector('simple', chunks) FROM bedrock_integration.bedrock_kb
    ```

    > 'また':1 '使い慣れたawsサービスを使用して':2 '生成ai機能をアプリケーションに安全に統合してデプロイできます':3

おっと、これは「aws」も検索できないですねぇ。。

## なんとかならないのか

「`simple`」ってのを、なにかいい感じにできたら良さそうな雰囲気を感じます。

以下のSQLを実行すると、対応するオプションがわかります。

```sql
SELECT cfgname FROM pg_ts_config;
```

> cfgname
simple
arabic
armenian
basque
catalan
danish
dutch
english
finnish
french
german
greek
hindi
hungarian
indonesian
irish
italian
lithuanian
nepali
norwegian
portuguese
romanian
russian
serbian
spanish
swedish
tamil
turkish
yiddish

japaneseがない（泣）
どうも、標準では対応していないようです。

また、[Bedrockナレッジベースのドキュメント](https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base-setup.html)にも、「`to_tsvector('simple', chunks)`で作成するように」とあるので、変えて動く保証もないように思います。。

うーん。。


## まとめ

Bedrockナレッジベースをつかってマネージドに、ハイブリッド検索をしたい場合はOpenSearch ServerlessかOpenSearch Serviceを使うのが良さそうですね。

OpenSearch Serverlessの全文検索を日本語対応する方法はこちらで記事にしてるので、よかったら参照ください。（OpenSearch Serviceも同じ手順でできると思います）

https://www.fsi.co.jp/blog/10661/


:::note warn
お前の検証は間違っている！本当は日本語でもちゃんと全文検索できるんだ！！　というご指摘を心の底からお待ちしております。
:::