を使って個人的備 忘録(まだ途中) Weaviate 2025/10/30 Jun Ohtani / @johtani 1

自己紹介 フリーランスエンジニア / コンサルタント 検索技術勉強会主催者の一人 検索システムの著者の一人 (ラムダノートより出版) 2

経緯 検索に関連するブログや記事をよく読む お客さんに紹介したりする けど、どのブログだったか忘れる。。。 それとは別にWeaviateを使って何かを作ろうとしていた 3

ということで? を使って個人的備忘録を作ることにした うろ覚えなのでキーワードだけの検索はちょっと RAGっぽい話なのでは? ベクトルデータベースでやりましょうか ステマも含んでいます Weaviate https://github.com/johtani/grimoire-keeper 4

構成 : スクレイピング:Jina AI Reader 要約+キーワード付与:Gemini チャンキング:Chonkie 保存+検索:Weaviate UI Slack or Web 5

登録の流れ 6

UI Slack スマホでも観てる 外でも見てるものを保存したい Web 検索はSlackだとつらかったのでWebを後から追加 7

スクレイピング Jina AI Reaer API https://jina.ai/reader ローカルも考えたけど… URLを渡し、Markdown形式で取得 いくつかオプションも リンクや画像をリストで抜き出すなど 最近、Elasticに吸収されたみたい (ブログ) 8

Jina AI Reader のサンプル(リクエスト) import requests url = “https://r.jina.ai/https://blog.johtani.info/blog/2025/07/14/intro-weaviate-quickstart/” headers = { “Accept”: “application/json”, “X-Md-Link-Style”: “discarded”, “X-Return-Format”: “markdown”, “X-With-Images-Summary”: “true”, “X-With-Links-Summary”: “true” } response = requests.get(url, headers=headers) print(response.text) 9

Jina AI Reader { } のサンプル(レスポンス) “code”: 200, “status”: 20000, “data”: { “images”: {}, “links”: { “@johtaniの日記 3rd”: “https://blog.johtani.info/”, … }, “title”: “Weaviate入門(Quickstart - Go言語編) …”, “description”: “johtaniの日記です。技術とか、…”, “url”: “https://blog.johtani.info/blog/2025/07/14/intro-weaviate-quickstart/”, “content”: “Weaviate入門(Quickstart - Go言語編) | @johtaniの日記 3rd… \n\n### クライアントの接続 \n\nまずは、Weaviate Cloudのクラスターへの接続情報が必要にです。 \n\n1.で作成したクラスターをクリックし、Cluster detailsの画面で以下の情報をコピーし、環境変数に設定します。\n\n…”, “publishedTime”: “Tue, 15 Jul 2025 14:16:16 GMT”, “metadata”: { “lang”: “ja”, … }, … }, … 10

要約+キーワード付与 を利用 LiteLLMでアクセス 簡単な検索には要約を検索 キーワード検索も活用して検索したい キーワード除外で検索から外したりも Gemini API 11

チャンキング:Chonkie https://docs.chonkie.ai/ の画像、テーブル、コードを判別 チャンキングの戦略が複数選択できる トークン数、センテンス、構造、意味など Markdown TODO セクションごとのタイトルなどがうまく取 れるか 12

Chonkie サンプルコード from chonkie import MarkdownChef, RecursiveChunker from chonkie.types import MarkdownDocument class ChunkingService: def init(self, chunk_size: int = 1000): self.chef = MarkdownChef() # markdown_jp.jsonのパスを取得 config_dir = Path(file).parent.parent / “config” recipe_path = config_dir / “markdown_jp.json” self.chunker = RecursiveChunker.from_recipe( path=str(recipe_path), chunk_size=chunk_size ) def chunk_text(self, text: str) -> list[str]: doc = self.chef.parse(text) chunked_doc = self.chunker.chunk_document(doc) return [chunk.text for chunk in chunked_doc.chunks] 13

保存+検索 https://weaviate.io/ を利用 AIネイティブなベクトルDB Goで実装されたOSSのベクトルDB Cloudサービスもある ベクトル検索、キーワード検索が可能 モデルプロバイダーで簡単に利用可能 Weaviate 14

のスキーマ(プロパティ) Weaviate client.collections.create( name=”GrimoireChunk”, description=”Grimoire Keeperで管理するWebページのチャンク”, properties=[ Property(name=”pageId”, data_type=DataType.INT), Property(name=”chunkId”, data_type=DataType.INT), Property(name=”url”, data_type=DataType.TEXT), Property(name=”title”, data_type=DataType.TEXT), Property(name=”memo”, data_type=DataType.TEXT), Property(name=”content”, data_type=DataType.TEXT), Property(name=”summary”, data_type=DataType.TEXT), Property(name=”keywords”, data_type=DataType.TEXT_ARRAY), Property(name=”createdAt”, data_type=DataType.DATE), Property(name=”isSummary”, data_type=DataType.BOOL), ], vector_config=[… ], ) 15

のスキーマ(ベクトル設定) Weaviate の を呼び出してベクトル作って登録してくれる OpenAI API [ Configure.Vectors.text2vec_openai( name=”content_vector”, source_properties=[“content”] ), Configure.Vectors.text2vec_openai( name=”title_vector”, source_properties=[“title”, “summary”], ), Configure.Vectors.text2vec_openai( name=”memo_vector”, source_properties=[“memo”] ), 16

のサンプル(登録) Weaviate collection = client.collections.get(“GrimoireChunk”) for i, chunk in enumerate(chunks): weaviate_object = { “pageId”: page_data.id, “chunkId”: i, “url”: page_data.url, “title”: page_data.title, “memo”: page_data.memo or “”, “content”: chunk, “summary”: page_data.summary or “”, “keywords”: json.loads(page_data.keywords or “[]”), “createdAt”: ( page_data.created_at.replace(tzinfo=None).isoformat() + “Z” if page_data.created_at.tzinfo is None else page_data.created_at.isoformat() ), “isSummary”: i == 0, } result = collection.data.insert(properties=weaviate_object) 17

のサンプル(検索) Weaviate collection = client.collections.get(“GrimoireChunk”) # クエリ実行 response = collection.query.near_text( query=query, target_vector=vector_name, limit=limit, filters=final_filter, return_metadata=MetadataQuery(certainty=True), ) 18

デモ? 19

デモ? 20

デモ? 21

デモ? 22

まとめ(+まだやりたいことがいっぱい) 便利ですね(ステマ) やりたいこと ハイブリッド検索 エージェントを活用した検索 Weaviate Multi-vector embeddings https://github.com/johtani/grimoire-keeper 23

の日本コミュニティ Weaviate Weaviate JP Community https://weaviate.connpass.com/ 24