50代ITエンジニアが学ぶLangChainその4 - RAG

こちらの続きです。

https://qiita.com/taka_yayoi/items/2e899f9c5e840ada8cc1

ノートブックはこちらです。

https://github.com/taka-yayoi/langchain_tutorial/blob/main/4.%20RAG.ipynb


# Retrieval Augmented Generation (RAG) アプリを構築する: パート1

LLMによって可能になる最も強力なアプリケーションの1つは、洗練された質問応答 (Q&A) チャットボットです。これらは特定のソース情報に関する質問に答えるアプリケーションです。これらのアプリケーションは、リトリーバル強化生成 ([RAG](https://python.langchain.com/docs/concepts/rag/)) として知られる技術を使用します。

これは複数パートのチュートリアルです:

- [パート1](https://python.langchain.com/docs/tutorials/rag/) (このガイド) では、RAGを紹介し、最小限の実装を説明します。
- [パート2](https://python.langchain.com/docs/tutorials/qa_chat_history/)では、会話スタイルのインタラクションやマルチステップのリトリーバルプロセスに対応するために実装を拡張します。

このチュートリアルでは、テキストデータソース上でシンプルなQ&Aアプリケーションを構築する方法を示します。途中で、典型的なQ&Aアーキテクチャについて説明し、より高度なQ&A技術のための追加リソースを強調します。また、LangSmithがアプリケーションのトレースと理解にどのように役立つかを見ていきます。アプリケーションが複雑になるにつれて、LangSmithはますます役立つようになります。

基本的なリトリーバルにすでに精通している場合は、[さまざまなリトリーバル技術の概要](https://python.langchain.com/docs/concepts/retrieval/)にも興味があるかもしれません。

:::note info
注: ここでは非構造化データのQ&Aに焦点を当てています。構造化データに対するRAGに興味がある場合は、[SQLデータに対する質問応答](https://python.langchain.com/docs/tutorials/sql_qa/)に関するチュートリアルをご覧ください。
:::

[Build a Retrieval Augmented Generation \(RAG\) App: Part 1 \| 🦜️🔗 LangChain](https://python.langchain.com/docs/tutorials/rag/)

## 概要

典型的なRAGアプリケーションには2つの主要なコンポーネントがあります:

- **インデックス作成:** ソースからデータを取り込み、インデックスを作成するパイプライン。*これは通常オフラインで行われます。*
- **リトリーバルと生成:** 実際のRAGチェーンで、実行時にユーザーのクエリを受け取り、インデックスから関連データを取得し、それをモデルに渡します。

注: このチュートリアルのインデックス作成部分は、[主にセマンティック検索のチュートリアル](https://python.langchain.com/docs/tutorials/retrievers/)に従います。

生データから回答までの最も一般的な完全なシーケンスは次のとおりです:

### インデックス作成

1. **ロード:** まず、データをロードする必要があります。これは[ドキュメントローダー](https://python.langchain.com/docs/concepts/document_loaders/)を使用して行います。
1. **分割:** [テキストスプリッター](https://python.langchain.com/docs/concepts/text_splitters/)は、大きな`Documents`を小さなチャンクに分割します。これは、データのインデックス作成やモデルに渡す際に役立ちます。大きなチャンクは検索が難しく、モデルの有限のコンテキストウィンドウに収まりません。
1. **保存:** 分割したデータを保存し、後で検索できるようにインデックスを作成する場所が必要です。これは通常、[ベクトルストア](https://python.langchain.com/docs/concepts/vectorstores/)と[エンベディング](https://python.langchain.com/docs/concepts/embedding_models/)モデルを使用して行います。

![](https://python.langchain.com/assets/images/rag_indexing-8160f90a90a33253d0154659cf7d453f.png)

### リトリーバルと生成

1. **リトリーバル:** ユーザー入力を受け取り、リトリーバーを使用してストレージから関連するスプリットを取得します。
1. **生成:** [チャットモデル](https://python.langchain.com/docs/concepts/chat_models/) / [LLM](https://python.langchain.com/docs/concepts/text_llms/)が、質問と取得したデータを含むプロンプトを使用して回答を生成します。

![](https://python.langchain.com/assets/images/rag_retrieval_generation-1046a4668d6bb08786ef73c56d4f228a.png)

データのインデックス作成が完了したら、[LangGraph](https://langchain-ai.github.io/langgraph/)をオーケストレーションフレームワークとして使用し、リトリーバルと生成のステップを実装します。

## セットアップ

```py
%pip install --quiet --upgrade langchain-text-splitters langchain-community langgraph langchain[openai] mlflow bs4
%restart_python
```

```py
import mlflow

# MLflow Tracingの有効化
mlflow.langchain.autolog()
```

```py
import os
os.environ["OPENAI_API_KEY"] = dbutils.secrets.get("demo-token-takaaki.yayoi", "openai_api_key")
```

## コンポーネント

LangChainの統合スイートから3つのコンポーネントを選択する必要があります。

[Chat model](https://python.langchain.com/docs/integrations/chat/)を選択します。

```py
from langchain.chat_models import init_chat_model

llm = init_chat_model("gpt-4o-mini", model_provider="openai")
```

[Embeddings model](https://python.langchain.com/docs/integrations/text_embedding/)を選択します。

```py
from langchain_openai import OpenAIEmbeddings

embeddings = OpenAIEmbeddings(model="text-embedding-3-large")
```

[Vector store](https://python.langchain.com/docs/integrations/vectorstores/)を選択します。

```py
from langchain_core.vectorstores import InMemoryVectorStore

vector_store = InMemoryVectorStore(embeddings)
```

## プレビュー

このガイドでは、ウェブサイトのコンテンツに関する質問に答えるアプリを作成します。使用する特定のウェブサイトは、私による[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)のブログ投稿であり、投稿の内容に関する質問をすることができます。

これを約50行のコードでシンプルなインデックス作成パイプラインとRAGチェーンを作成して行うことができます。

```py
import bs4
from langchain import hub
from langchain_community.document_loaders import WebBaseLoader
from langchain_core.documents import Document
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langgraph.graph import START, StateGraph
from typing_extensions import List, TypedDict

# ブログの内容をロードしてチャンクに分割
loader = WebBaseLoader(
    web_paths=("https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d",),
    bs_kwargs=dict(
        parse_only=bs4.SoupStrainer(
            class_=("p-items_main")
        )
    ),
)
docs = loader.load()

text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
all_splits = text_splitter.split_documents(docs)

# チャンクをインデックス化
_ = vector_store.add_documents(documents=all_splits)

# 質問応答のためのプロンプトを定義
prompt = hub.pull("rlm/rag-prompt")


# アプリケーションの状態を定義
class State(TypedDict):
    question: str
    context: List[Document]
    answer: str


# アプリケーションのステップを定義
def retrieve(state: State):
    retrieved_docs = vector_store.similarity_search(state["question"])
    return {"context": retrieved_docs}


def generate(state: State):
    docs_content = "\n\n".join(doc.page_content for doc in state["context"])
    messages = prompt.invoke({"question": state["question"], "context": docs_content})
    response = llm.invoke(messages)
    return {"answer": response.content}


# アプリケーションをコンパイルしてテスト
graph_builder = StateGraph(State).add_sequence([retrieve, generate])
graph_builder.add_edge(START, "retrieve")
graph = graph_builder.compile()
```

ドキュメントを確認します。

```py
docs
```
```
[Document(metadata={'source': 'https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d'}, page_content='infoMore than 1 year has passed since last update.flag記事投稿キャンペーン 「2024年!初アウトプットをしよう」@taka_yayoi(Takaaki Yayoi)inデータブリックス・ジャパン株式会社はじめてのDatabricksDatabricksLast updated at 2024-01-11Posted at 2024-01-07Databricks弥生です。今年もよろしくお願いします。Databricksに入社してからはや3年が経ち、これまでに入門書的な記事をいくつか書いてきています。\n\n\n\n\n\n\nクイックスタートガイドについては本も出しました。\n\n\n\nしかし、これらの内容が古くなってきているのもありますし、今更ながら「はじめてのDatabricks」の記事を書いていないことに気づきましたので書きます。\n\n対象読者\n\nDatabricksの環境(ワークスペース)が構築されている。ワークスペースがない場合には無料トライアルに申し込んでください。\nDatabricksワークスペースのユーザーが払い出されている。\nこれからDatabricksを使い始めるが、どこから手をつけたらいいのか悩んでいる。\n\n\nお悩み事\nこれまでに以下のようなお悩み事を伺っているので、可能な限り解消していきたいと思います。\n\nDatabricksとは何かがわからない、何ができるのかわからない\nJuypter NotebookやGoogle Colaboratoryと何が違うのかがわからない\nDatabricksをどう使えばいいのかがわからない\n\n画面が英語でとっつきにくい\nDatabricksのメニュー項目が多すぎてどれがどれかがわからない\n不用意にデータやファイルを上書きしてしまわないかが怖い\n\n\n\n\nDatabricksとは\n以下にまとめていますが、すごくざっくり言えばデータやAIの活用というユースケースで必要となるさまざまな便利機能を搭載しているノートブック開発環境です。ざっくりしすぎかもしれませんが、データサイエンティストやデータエンジニアの方が最初に触れるインタフェースはJupyter NotebookやGoogle Colaboratoryと同様のノートブックです。\n\n\n\n\nJuypter NotebookやGoogle Colaboratoryとの違い\n\nJupyter Notebookとの違い\nこちらにまとめています。\n\n\n\nDatabricksではビルトインのビジュアライゼーションの機能があるなど、細かいところを挙げると色々ありますが、大きな違いはラップトップで稼働させるのか、クラウドで稼働させるのかだと思います。稼働する場所で何が違うのかというと:\n\n\n\n\nJupyter Notebook\nDatabricks\n\n\n\n\n計算リソース\nJuypter Notebookが稼働しているラップトップ、サーバーのリソースに制限を受けます。多くの場合、pandasの利用が前提となるのでメモリーの制約を受けます。\nクラウドプロバイダー(AWS/Azure/GCP)が提供するリソースを理論上無制限に活用できます。pandasに加えてSparkも活用できるので、並列処理による恩恵を享受することができます。\n\n\nコラボレーション\nラップトップで動作しているJupyter Notebookでの他のユーザーとのコラボレーションは限定的であり、JupyterHubを用いたとしてもその機能は限定的です。\n複数ユーザーによるコラボレーションを前提としており、ノートブックやデータに対するアクセス制御やノートブックの同時参照、同時編集をサポートしています。\n\n\nガバナンス\nラップトップで動作しているJupyter Notebookでは、個人のデータサイエンティストによる管理しか行えず、企業全体でのデータやコード、機械学習モデルの管理を統一することができません。\n\nMLOpsを前提としており、データ、コード、機械学習モデルは全てUnity Catalogによって管理されます。\n\n\n本格運用(Production)\nラップトップ上で実験的にPythonを実行するには適してますが、本格運用するためにジョブを組むには別のシステムが必要となります。\nDatabricksにはワークフローの機能が搭載されているので、実験・テストを経たロジックを簡単に本格運用に移行することができます。また、さまざまなAPIを公開しているので、他のシステムとの連携も容易です。\n\n\n\n\nGoogle Colaboratoryとの違い\nGoogle Colaboratoryもクラウドで稼働するのでJuypter Notebookのリソースやコラボレーションの課題はある程度解消されますが、以下で詳細に比較が行われています。\n\n\n\n\n\n\n\nGoogle Colaboratory\nDatabricks\n\n\n\n\nホスティング\nGoogleがホスティングしているので、データをGoogleに渡すことになります。\n自分のクラウドアカウントにホスティングするので、データをDatabricksに渡す必要はありません。(サーバレスを利用する際にはこの限りではありません)\n\n\nデータソース\nGoogle Drive\nUnity Catalogやご自身のクラウドアカウントのクラウドストレージ\n\n\n\nガバナンスや本格運用などその他の違いに関してはJupyter Notebookと同様です。Google ColaboratoryではGPUを利用することができますが、あくまでGoogleが使用を許可しているスペックのみです。Databricksの場合はお客様が契約しているクラウドアカウントにおけるクォータの範囲内であれば、自由に計算資源を構成・利用することができます。\n\nDatabricksの使い方\n私は全体像を大まかに理解してから、必要に応じて詳細に踏み込むアプローチが好きです。最初から全てを理解しようとしていたら、いつまで経っても一歩を踏み出せません。\nということで、使い方のイメージをざっくり書いてみました。\n\nユーザーはデータサイエンティストやデータエンジニアです。それ以外の登場人物はこちらです。\n\n\nノートブック: そのままです。Pythonなどでロジックを記述します。\n\n計算資源: Jupyter Notebookを利用している際にはあまり意識しないかもしれませんが、ラップトップであればラップトップのCPUやメモリーを使ってプログラムが実行されます。\n\nデータベース・ファイルシステム: データを読み込んだり永続化するにはデータベースやファイルシステムが必要となります。 Jupyter NotebookであればローカルのファイルシステムやODBC/JDBC経由で接続したデータベースになるでしょう。\n\nなので、Databricksを使うにしても、使い方にはJupyter Notebookと大きな違いはないと言えます(LLMなど複雑なことをやり始めるとこの限りではありませんが)。\nとは言え、これではあまりにも抽象的なので、以下のステップを経てDatabricksでどういうことができるのかをウォークスルーしていきます。\n\nDatabricksワークスペースへのアクセス\nノートブックの作成\n計算資源の準備\nデータの読み込み\nデータの加工\nデータの保存\n\n\nDatabricksワークスペースへのアクセス\nDatabricksの環境はお客様ごとに構築するので、ワークスペースと呼ばれる作業環境のURLもお客様固有のものとなります。環境構築をされた方にURLを確認してください。\n初回アクセスの際、画面がすべて英語で面食らうかもしれません。ブラウザの言語設定が日本語になっていれば、右上に言語設定のダイアログが表示されます。日本語を使うをクリックしてください。\n\nGUIが日本語に切り替わります。\n\nダイアログが表示されない場合には、以下の手順に従ってください。\n\n画面右上のメールアドレスをクリックして、User Settingsをクリック。\n\n\nUserの下にあるPreferenceをクリック。\n\n\n\nLanguageから日本語を選択。\n\n\n\n以下のような画面が表示されるはずです。\n\nまずは、画面構成に慣れましょう。これもざっくり。\n\nまず慣れる必要があるのは、画面左にあるサイドメニューです。Databricksの主要機能にアクセスする際に使用することになります。サイドメニュー上にカーソルを移動するとメニューが展開されます。\n\nここでも最初から全てを理解するのではなく、以下の項目にフォーカスします。他の機能は必要になったら勉強すればいいのです。\n\n\n新規: Databricksにおけるさまざまなアセット(資産)を作成するときに使います。ノートブックやクラスターなど色々なアセットを作成できます。\n\nワークスペース: アセットはフォルダで整理することができます。このフォルダ階層にアクセスするために使うメニュー項目がワークスペースです。\n\nカタログ: Databricksにビルトインされているデータベースのようなものです。テーブルだけでなくファイルや機械学習モデルなども格納することができます。\n\nクラスター: Databricksにおける計算資源です。ノートブックの編集では計算資源は不要ですが、プログラムを実行する際にはクラスターは必須となります。\n\n\nノートブックの作成\n\nDatabricksでもプログラムを実行するにはノートブックを作成する必要があります(IDE連携をするなどすればPythonファイルを実行することもできます)。ノートブックを作成する前に、Databricksワークスペースのフォルダ階層を理解しましょう。\n上述したようにDatabricksの環境は複数ユーザーによるコラボレーションを前提としています。このため、以下のフォルダがデフォルトで作成されます。\n\nホームフォルダ: 各ユーザーごとのホームフォルダ。自分のアセットはデフォルトでホームフォルダ配下に作成されます。アクセス権を付与しない限り、他のユーザーがあなたのアセットにアクセスすることはできません。しかし、管理ユーザーはこの限りではありません。\n\n\nWorkspace: ワークスペースに登録されたユーザーそれぞれのホームフォルダを格納します。\n\n\nShared: すべてのユーザーが読み書きできるフォルダです。ノートブックの共有などの目的で使用します。\nお気に入り: ノートブックやフォルダをお気に入りに登録するとこちらに表示されます。ショートカットできます。\nゴミ箱: 削除されたノートブックなどは一定期間こちらに格納されます。元に戻すこともできます。\n\n自分のアセットはホームフォルダ配下、削除されたアセットはゴミ箱をまず覚えておくと良いかと思います。\nホームフォルダ直下にノートブックを作成しても構いませんが、整理できるように私は作業内容ごとにフォルダを作成しています。ワークスペースを表示している状態で右上の追加をクリックします。\n\nフォルダを選択します。\n\nフォルダ名を記入します。\n\n\nノートブックを作成する手段はいくつかありますが、上と同じように追加 > ノートブックを選択します。\n\nこれでノートブックを作成できました。\n\nここで、ノートブックの画面にも慣れておきましょう。ノートブックのインタフェース自体はJupyterやColaboratoryと大きな違いはないと思います。\n\nノートブック名はクリックで編集できます。\n\n今回、便利メニューの説明は割愛します。目次の表示、ワークスペースフォルダへのアクセス、Unity Catalogメタストアへのアクセス、AIアシスタント、ノートブックコメント、機械学習モデルのトラッキング、バージョン履歴、変数エクスプローラ、ライブラリエクスプローラなどを利用できます。\n今回重要になるのはノートブック本体とクラスターセレクターです。ノートブックにプログラムを記述するのは当たり前ですが、Databricksの計算資源であるクラスターが必要となります。\n\n計算資源の準備\n\nDatabricksクラスターはクラウドプロバイダーの提供する仮想マシン(EC2/VMなど)をカプセル化して、さまざまな要件の処理に柔軟に対応できる機能を提供します。以下のような機能を提供します。\n\nプレインストールされるソフトウェア(Python/Sparkの実行環境、scikit-learn/tensorflowなど)\nライブラリの追加インストール\nオートスケーリング(クラスターの実態は複数台の仮想マシンです。クラスターの由来はここにあります。処理の負荷などに応じて自動でマシン数を増減させます)\n自動停止(クラウドで一番お金がかかるのは計算資源です。使われていない計算資源はコスト的に一番の無駄です)\n\nということで、クラスターを作成しましょう。サイドメニューのクラスターをクリックします。\n\nすでに作成済みのクラスターがあれば一覧に表示されます。なお、上の画像ではすべてのクラスターの状態は停止状態です。この状態ではお金は全くかかっていません。Databricksもクラウドプロバイダーも計算資源の費用は稼働している状態にのみ発生します。Databricksにおける計算資源、クラスターの考え方としては揮発性(ephemerarl) というものがあります。これは、処理が必要なときだけ計算資源をかき集めてクラスターを構成して、処理が終わったら解放するという使い方に立脚しています。ラップトップやオンプレミスのサーバーは所有している計算資源=活用できる計算資源となりますが、クラウドリソースを活用する際にはその制限を気にする必要はありません。処理対象のデータ構造、データ量、処理内容に応じて計算資源を充当できるのがクラウドを活用することの大きなメリットと言えます(コストも考慮する必要はありますが)。ここで作成するクラスターというのは計算資源のメタデータであって、そのメタデータに従って計算資源が構成されるという考え方になります。言い方はあれですが「使い捨て」の計算資源となります。\n右上のコンピューティングを作成でクラスターを作成できるのですが、クイックに最小規模のクラスターを作成するにはその左にあるPersonal Computeで作成をクリックします。パーソナルコンピュートとはクイックにクラスターを作成できるテンプレートのようなものです。Databricksクラスターは詳細な設定を含めると、台数だけではなくインスタンスタイプ、initスクリプト、ソフトウェアバージョンなどなど多様な設定が可能です。それらを毎回選択するのは手間なので、クイックに作業に取り掛かれるようにするためのパーソナルコンピュートが用意されています。なお、以下のスペックとなります。\n\nシングルノードのクラスター\n最新のDatabricks機械学習ランタイムをインストール\n\nこれをクリックするとデフォルト設定が行われた状態でクラスター作成画面が表示されます。コンピューティングを作成をクリックすることでクラスターが作成されます。\n\n仮想マシンの取得、ソフトウェアのインストールが行われるので5分ほどお待ちください。クラスター名の右にインジケータが表示されます。\n\n起動すると以下のような画面になります。\n\nしかし、これで終わりではありません。このクラスターは起動しているだけであり、上で作成したノートブックの処理をこのクラスターで実行するという指示を行う必要があります。そのためにはノートブックの画面に戻る必要があります。サイドメニューのワークスペースにアクセスして、作成したフォルダ、ノートブックにアクセスします。\n\nそして、右上のクラスターセレクターをクリックします。\n\n起動しているクラスターが一覧に表示されるはずです。クラスターを選択します。\n\nこれでプログラムを実行できるようになりました。\n\nお約束のプログラムを実行しましょう。セルに以下を記述します。\n\nPython\nprint("Hello Databricks!")\n\n\n\nセルの右上にある▶️をクリックし、セルを実行をクリックします。\n\n動きました！\n\n\n\n注意\nエラーが出る場合には、ノートブック名の右にある言語がPythonであるかどうかを確認してください。\n\n\n\n\nデータの読み込み\n\nこれでDatabricksでプログラムを実行できるようになりました。早速データを処理していきましょう。ノートブックにセルを追加するには、ノートブックの上か下の端にカーソルを移動します。+ ボタンが表示されるのでこれをクリックします。\n\n\nDatabricksにおいてデータやファイル、機械学習モデルを管理するためのソリューションはUnity Catalogです。名前の通り、カタログソリューションであり上述のアセットのアクセス管理、監査ログ、依存関係などをまるっと面倒見てくれます。色々な機能を提供しますが、ここではデータの読み書きにフォーカスします。\nUnity Catalogにはすぐに利用できるサンプルデータが格納されているので、ここではそれを使います。Unity Catalogで管理されているデータをクイックに確認するにはカタログエクスプローラが便利です。サイドメニューのカタログをクリックします。スキーマやデータを簡単に確認できます。\n\n\nノートブックに戻ります。ここでのノートブックはPythonなので、Pythonで処理するのが素直だと思うのですが、データベースの処理をするならSQLの方がわかりやすいので、PythonノートブックでSQLを使います。これもDatabricksの提供する柔軟性の一つです。セルの先頭にマジックコマンド%sqlを追加することでそのセルの言語をSQLに切り替えることができます。他の言語(R、SQL、Python)も同様です。\n\nSQL\n%sql\nselect * from samples.tpch.orders limit 1000;\n\n\n\nテーブル名をsamples.tpch.ordersと指定していることに注意してください。Unity Catalogで管理されるテーブルは3階層の名前空間で管理されます。<カタログ>.<スキーマ(データベース)>.<テーブル>で個々のテーブルを特定します。テーブルだろうがファイルだろうが、データを読み書きする際には、どのデータを対象に処理をしているのかを意識することが重要です。テーブルなら上記の名前空間、ファイルならパスとなります。よくある間違いの一つは意図しないテーブルやパスのファイルを読み込んだり、書き込んだりしていただと思います。\n読み込み処理はこれで終わりではありません。上のスクリーンショットにはテーブルの右に + が表示されてます。これをクリックします。可視化を選択します。\n\nこちらの手順に従ってビジュアライゼーションの設定を行います。\n\nこれでノートブックにグラフを追加することができました。Jupyterなどであればmatplotlibやseabornで可視化のロジックを記述しないとグラフにすることができませんが、Databricksならこの辺りはお手軽にできます。もちろん、matplotlibやseabornも使えます。\n\n\nデータの加工\nこちらでも書いていますが、どのような変換を行いたいのかに応じて処理を実装することになります。\n\n\n\nここではすでに別の方(データエンジニアなど)によってデータが準備されていることを前提にします。自分でデータを準備する場合にはこちらをご一読ください。\n\n\n\n例えば、対象データの特定の列と特定の行に限定したいというフィルタリング処理を行ってみます。行の絞り込みではo_orderdateとo_totalpriceにフィルタリング条件を適用しています。\n\nSQL\n%sql\nSELECT\n  o_orderkey,\n  o_custkey,\n  o_orderstatus,\n  o_totalprice,\n  o_orderdate,\n  o_orderpriority\nFROM\n  samples.tpch.orders\nWHERE\n  o_orderdate = "1998-07-01"\n  AND o_totalprice >= 100000\n\n\n\nこのように、どのような形状のデータが必要なのかという要件に応じてデータを加工することになります。\n\nデータの書き込み\n上述したように、どこに書き込みを行うのかを意識することが重要です。特に書き込みの際には対象データを上書きしてしまう可能性があるので注意してください。当たり前の話ですが、どんなに仕組みが洗練されたとしても既存データに対して書き込み権限があるのであれば、データの上書きは可能です。\n\n\n注意\n管理者の方向けの話となりますが、誤った操作でデータを上書きしてしまうというのは日常的に起こる事故といえます。このような事故を避けるためにも環境の分離(開発用/本番用)や適切なアクセス権の設定を行うことをご検討ください。なお、Databricksにおけるデフォルトのテーブル形式であるDelta Lakeではテーブルの更新ログが自動で記録されますので、テーブル状態のロールバックは可能です。\n\n\n\nテーブルへの書き込み\n加工したデータを自分用のカタログ、スキーマ(データベース)配下のテーブルとして保存するのがよくある使い方でしょう。ここでは、自分用のカタログtakaakiyayoi_catalog、スキーマtpchが作成されており、権限が付与されているものとします。カタログの作成権限があるかどうか、自分が使えるカタログがあるのかについては管理者の方に確認してください。\n\nここがテーブルの書き込み先となります。一旦SQLでやり切るのでいわゆるCTAS(Create Table As Select)構文を使います。作成するテーブル名は上述のカタログとスキーマを使うのでtakaakiyayoi_catalog.tpch.orders_199807とします。\n\nSQL\n%sql\nCREATE TABLE takaakiyayoi_catalog.tpch.orders_199807 AS\nSELECT\n  o_orderkey,\n  o_custkey,\n  o_orderstatus,\n  o_totalprice,\n  o_orderdate,\n  o_orderpriority\nFROM\n  samples.tpch.orders\nWHERE\n  o_orderdate = "1998-07-01"\n  AND o_totalprice >= 100000\n\n\nエラーが出なければ問題なくテーブルを書き込めています。\n\nカタログエクスプローラにアクセスすると、作成されたテーブルを確認できます。\n\n\nこれでデータを永続化することができました。もう一つ重要な観点が権限です。デフォルトではテーブルの作成者(あなた)のみがこのテーブルにアクセスできます。このデータを他のユーザーと共有したい場合には、権限を付与することで他のユーザーの方も活用できるようになります。このような機能もデータによるコラボレーションを促進するためのものです。\n\n\nずっとSQLで処理を記述してきましたが、Pythonでも同様のことは可能です。ここまでSparkの話はしてきていませんでしたが、Databricksの処理の肝になっているのがApache Sparkです。大量データの処理を効率的に行うための分散処理フレームワークです。ここでは詳細に踏み込みませんが、これもざっくりいうとペタバイトであろうがエクサバイトのデータであろうが、マシン台数を増やして並列に高速に処理できる仕組みです。この処理には、上で行ったようなデータの加工や機械学習モデルのトレーニングなどさまざまなものが含まれます。そして、Sparkの長所の一つにさまざまな言語のサポートがあります。上でSQLを実行していましたが、これはSparkによって処理されています。それ以外にもPython、R、Scalaもサポートしています。Pythonを使う際にはSparkに対するPython APIであるPySparkを使います。\nプログラムとしてロジックを記述するのであれば、SQLよりもPythonがおすすめとなります。ループや条件分岐をSQLで記述するのは相当難易度高いです。\nただ、「PySparkは敷居が高い」という声も伺います。しかし、pandasやRを使いこなしている方であれば、PySparkは方言の一つと言えるのではないかと個人的には思いますし、パフォーマンス最適化などの話が出てくると細かい設定が必要となりますので、早い段階でPySparkに慣れていただくのが良いかと思います。「PySparkをマスターするぜ」という気概のある方はこのあたりからいかがでしょうか。\n\n\n\n\n\n\nあと、SparkでPandas APIを実行する手段もあります。\n\n\n\nなお、上のSQLのロジックをPySparkで実装すると以下のようになります。\n\nPython\nsdf = spark.table("samples.tpch.orders")\n(\n    sdf.select(\n        [\n            "o_orderkey",\n            "o_custkey",\n            "o_orderstatus",\n            "o_totalprice",\n            "o_orderdate",\n            "o_orderpriority",\n        ]\n    )\n    .filter("o_orderdate = \'1998-07-01\' AND o_totalprice >= 100000")\n    .write.saveAsTable("takaakiyayoi_catalog.tpch.orders_199807")\n)\n\n\nこのように、データフレームを保存するのであればテーブルとして保存するのがおすすめです。カタログエクスプローラで容易にメタデータを確認できますし、他のユーザーへの共有も楽です。\n\nボリュームへの書き込み\nファイルとして保存したい場合には、ボリュームを活用ください。Unity Catalogで管理されるファイルシステムのマウントポイントです。ボリュームでもUnity Catalogの名前空間の考え方は踏襲されています。パスは/Volumes/takaakiyayoi_catalog/japan_covid_analysis/covid_dataのように/Volumes/<カタログ>/<スキーマ>/<ボリューム>となります。pandas/PySpark/シェルコマンドなど使うツールに関係なくこれらのファイルにアクセスできます。\n\n以下のようにpandasで読み込めます。\n\nPython\nimport pandas as pd\n\ncovid_pdf = pd.read_csv(\n    "/Volumes/takaakiyayoi_catalog/japan_covid_analysis/covid_data/newly_confirmed_cases_daily.csv"\n)\ndisplay(covid_pdf)\n\n\n\nちなみに上のdisplay関数はDatabricksで使える便利コマンドで、データフレームを表示する際にお使いください。上述の可視化機能も利用できます。\nPySparkでも読み込めます。\n\nPython\ncovid_df = spark.read.csv(\n    "/Volumes/takaakiyayoi_catalog/japan_covid_analysis/covid_data/newly_confirmed_cases_daily.csv",\n    header=True,\n)\ndisplay(covid_df)\n\n\n\nシェルコマンドでもアクセスできます。シェルコマンドを実行するにはマジックコマンド%shを使います。\n%sh\nhead /Volumes/takaakiyayoi_catalog/japan_covid_analysis/covid_data/newly_confirmed_cases_daily.csv\n\nDate,ALL,Hokkaido,Aomori,Iwate,Miyagi,Akita,Yamagata,Fukushima,Ibaraki,Tochigi,Gunma,Saitama,Chiba,Tokyo,Kanagawa,Niigata,Toyama,Ishikawa,Fukui,Yamanashi,Nagano,Gifu,Shizuoka,Aichi,Mie,Shiga,Kyoto,Osaka,Hyogo,Nara,Wakayama,Tottori,Shimane,Okayama,Hiroshima,Yamaguchi,Tokushima,Kagawa,Ehime,Kochi,Fukuoka,Saga,Nagasaki,Kumamoto,Oita,Miyazaki,Kagoshima,Okinawa\n2020/1/16,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n2020/1/17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n2020/1/18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n2020/1/19,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n2020/1/20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n2020/1/21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n2020/1/22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n2020/1/23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n2020/1/24,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n\npandasデータフレームをCSVとしてボリュームに保存します。\n\nPython\ncovid_pdf.to_csv("/Volumes/takaakiyayoi_catalog/japan_covid_analysis/covid_data/pandas_data.csv")\n\n\n保存されました。\n\n\n上書きの回避策\n最後にもう一度上書きの件ですが、Sparkの場合には防御機構があります。例えば、テーブルを再度作成しようとすると以下のようにエラーとなりテーブルは上書きされません。すでにテーブルが存在しているというメッセージです。\n\nTableAlreadyExistsException: [TABLE_OR_VIEW_ALREADY_EXISTS] Cannot create table or view tpch.orders_199807 because it already exists.\n\nこのような場合、明示的に上書きを指示することができます。CREATE OR REPLACE TABLEを使います。テーブルが存在する場合にはデータを洗い替えするコマンドです。\n\nSQL\n%sql\nCREATE OR REPLACE TABLE takaakiyayoi_catalog.tpch.orders_199807 AS\nSELECT\n  o_orderkey,\n  o_custkey,\n  o_orderstatus,\n  o_totalprice,\n  o_orderdate,\n  o_orderpriority\nFROM\n  samples.tpch.orders\nWHERE\n  o_orderdate = "1998-07-01"\n  AND o_totalprice >= 100000\n\n\nPySparkでも同様です。テーブルが存在する場合にはSQLの際と同じエラーとなります。明示的に上書きを指示するには、writeの後にmode("overwrite")を指定します。\n\nPython\nsdf = spark.table("samples.tpch.orders")\n(\n    sdf.select(\n        [\n            "o_orderkey",\n            "o_custkey",\n            "o_orderstatus",\n            "o_totalprice",\n            "o_orderdate",\n            "o_orderpriority",\n        ]\n    )\n    .filter("o_orderdate = \'1998-07-01\' AND o_totalprice >= 100000")\n    .write.mode("overwrite").saveAsTable("takaakiyayoi_catalog.tpch.orders_199807")\n)\n\n\nですので、通常Sparkを使ってデータを書き込む際に上書きを心配する必要はないのですが、最悪のパターンは明示的に上書きを指定していることを忘れて上書きしてしまったというものです。これは、上述のどこに書き込みを行うのかに加えて、どのAPIのどの書き込みモードを使っているのかについても注意を払う以外に対策はありません。逆にこれらを意識しないでプログラムを実行しているのであれば、それによるリスクを想像していただき注意深くコーディングすることをお勧めします。と言っている私もたまにやってしまいます。\n\nまとめ\n書き込みのセクションは注意すべきことが多いので量が増えてしまいましたが、以下を注意いただきつつDatabricksを活用いただけると幸いです。\n\nデータの読み書きはテーブルがお勧めです。アクセスが容易で上書きしたとしてもロールバックが簡単です。\nどのテーブル、ファイルを読み込んでいるのかを常に意識ください。\nどのテーブル、ファイルに書き込みを行うのかを常に意識ください。\nどのAPIのどの書き込みモードを使っているのか。明示的に上書きを指定している場合、それは適切なものであるのかをご確認ください。\n\nそして、「これだとJupyter Notebookと大差ないのでは？」と思われた方もいらっしゃるかもしれませんが、これは「はじめてのDatabricks」です。ここでご紹介したのはDatabricksのほんの一部の機能です。\nこちらに説明があるように、Databricksは以下のような用途でご活用いただけます。\n\nデータ処理ワークフローのスケジューリングと管理\nダッシュボードとビジュアライゼーションの生成\nセキュリティー、ガバナンス、高可用性、およびディザスタリカバリーの管理\nデータの検出、アノテーション、探索\n機械学習 (ML) のモデリング、追跡、モデルサービング\n生成AI ソリューション\n\n本書ではビジュアライゼーションとガバナンスの一部に触れたに過ぎません。それ以外の機能についても今後紹介してこうと思いますし、これまでに記述した記事はこちらにありますので、ご興味のある方は一覧いただけると幸いです。\n最後になりますが、クラスターが起動している間課金が発生しますので、使い終わったクラスターは停止しましょう。\n\n\n参考資料\n\nDatabricksとは｜Databricks on AWS\nDatabricksノートブック入門 | Databricks on AWS\nコンピュート | Databricks on AWS\nDatabricks での探索的データ分析 : ツールとテクニック | Databricks on AWS\nビジュアライゼーションの種類 |Databricks on AWS\n\n\nDatabricksクイックスタートガイド\nDatabricksクイックスタートガイド\n\nDatabricks無料トライアル\nDatabricks無料トライアル\n39Go to list of users who liked27comment0Go to list of commentsRegister as a new user and use Qiita more convenientlyYou get articles that match your needsYou can efficiently read back useful informationYou can use dark themeWhat you can do with signing upSign upLogin')]
```

グラフも確認します。

```py
from IPython.display import Image, display
display(Image(graph.get_graph().draw_mermaid_png()))
```

まさにRAGです。

![download.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/8fcb8a32-b286-45fc-bb2d-209eabcf5726.png)

問い合わせます。

```py
response = graph.invoke({"question": "DatabricksとJupyter Notebookの違いは？"})
print(response["answer"])
```

```
Databricksはクラウドベースのノートブック開発環境で、計算リソースが理論上無制限に利用でき、複数ユーザーとの協力やデータ管理が容易です。一方、Jupyter Notebookはラップトップやローカルサーバー上で動作し、リソースが制限され、コラボレーション機能も限られています。従って、Databricksは大規模データ処理や運用に適していますが、Jupyter Notebookは主にローカル環境での実験的な利用に向いています。
```

トレースでもRAGの挙動をしていることを確認できます。

![Screenshot 2025-03-10 at 8.22.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/492ddbbf-5eec-4dc2-ad70-dbae031afb01.png)

次で最後です。RAGと来たらエージェント。

https://qiita.com/taka_yayoi/items/61cec4bcbb6814d2d229


### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)