deeplake について
deeplakeは、Deeplakeのマネージドテーブルを扱うエージェントや開発者向けのPythonおよびNode.js/TypeScript SDKです。データ取り込み、テーブル管理、クエリ、データセットへの直接アクセスに対応します。
主な機能
- 01PythonとNode.js/TypeScriptのSDK
- 02ファイルと構造化データの取り込み
- 03テーブルの作成と管理
- 04チェーン式クエリビルダーとSQLクエリ
- 05バッチ処理や機械学習向けのデータセットを開く機能
活用シーン
- 01マネージドテーブルへのファイル取り込み
- 02条件や上限を指定したテーブルレコードの検索
- 03トレーニングループ用のデータセットを開く
- 04テーブルデータのバッチ読み込み
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ activeloopai/ deeplake-skills --skill deeplakeインストール後、Claude Code で/deeplakeを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
examples.mdformats.mdreference.md詳細
Deeplake Managed Service SDK
Deeplake のマネージドテーブルにデータを取り込むための、エージェントに使いやすい SDK です。 Deeplake でデータを保存、取り込み、またはクエリしたい場合に、このスキルを使用します。 Python と Node.js/TypeScript の両方で利用できます。
クイックリファレンス
Python
pip install deeplake # uv add deeplake
Python のインポート(主な方法):
from deeplake import Client
# Async variant (requires aiohttp: pip install aiohttp):
from deeplake.managed import AsyncClient
from deeplake import Client
# Initialize -- token from DEEPLAKE_API_KEY env var, workspace defaults to "default"
client = Client()
client = Client(token="dl_xxx", workspace_id="my-workspace")
# Ingest files (FILE schema)
client.ingest("videos", {"path": ["video1.mp4", "video2.mp4"]}, schema={"path": "FILE"})
# Ingest structured data with indexes for search
client.ingest("embeddings", {
"text": ["doc1", "doc2", "doc3"],
"embedding": [[0.1, 0.2, ...], [0.3, 0.4, ...], [0.5, 0.6, ...]],
}, index=["embedding", "text"])
# Ingest from HuggingFace
client.ingest("cifar", {"_huggingface": "cifar10"})
# Ingest with format object (see formats.md for CocoPanoptic, Coco, LeRobot, custom)
client.ingest("table", format=my_format)
# Fluent query
results = client.table("videos").select("id", "text").where("file_id = $1", "abc").limit(10)()
# Raw SQL
results = client.query("SELECT * FROM videos LIMIT 10")
# Vector similarity search -- through client.query() the vector must be
# INLINED, not passed as $1 (see "Querying" below for why)
from deeplake.managed import vector_literal
results = client.query(f"""
SELECT id, text, embedding::float4[] <#> {vector_literal(query_embedding)} AS similarity
FROM embeddings ORDER BY similarity DESC LIMIT 10
""")
# Create an empty table with an explicit schema (no data yet)
client.create_table("docs", {
"id": "TEXT",
"embedding": "EMBEDDING(1536)", # NOT bare "EMBEDDING" — keep the dimension
}, index={"id": "inverted_index", "embedding": "clustered"})
# Table management
client.list_tables()
client.drop_table("old_table")
client.create_index("embeddings", "embedding", index_type="clustered")
client.drop_index("embeddings", "embedding")
client.describe_table("embeddings") # {col: {"type": ..., "index": ...}}
# Open a table without taking write access
ds = client.open_table("embeddings", read_only=True)
Node.js / TypeScript
npm install deeplake
TypeScript のインポート:
import { ManagedClient, initializeWasm } from 'deeplake';
WASM の初期化(すべての操作の前に必要):
await initializeWasm();
ManagedClient を使った操作(取り込み、クエリなど)を実行する前に、起動時に initializeWasm() を一度呼び出してください。基盤となる WASM モジュールを初期化します。
import { ManagedClient, initializeWasm } from 'deeplake';
await initializeWasm();
const client = new ManagedClient({ token: 'dl_xxx', workspaceId: 'my-workspace' });
// Ingest files (FILE schema)
await client.ingest("videos", { path: ["video1.mp4"] }, { schema: { path: "FILE" } });
// Ingest structured data
await client.ingest("embeddings", {
text: ["doc1", "doc2"],
embedding: [[0.1, 0.2], [0.3, 0.4]],
});
// Ingest with format object (see formats.md)
await client.ingest("table", null, { format: myFormat });
// Fluent query (use .execute())
const results = await client.table("videos")
.select("id", "text").where("file_id = $1", "abc").limit(10).execute();
// Raw SQL
const rows = await client.query("SELECT * FROM videos LIMIT 10");
// Create an empty table with an explicit schema (no data yet)
await client.createTable("docs", {
id: "TEXT",
embedding: "EMBEDDING(1536)", // NOT bare "EMBEDDING" — keep the dimension
}, { index: { id: "inverted_index", embedding: "clustered" } });
// Table management
await client.listTables();
await client.dropTable("old_table");
await client.createIndex("embeddings", "embedding", { indexType: "clustered" });
await client.dropIndex("embeddings", "embedding");
await client.describeTable("embeddings"); // {col: {type, index}}
// Open a table without taking write access
const ds = await client.openTable("embeddings", true);
依存関係と前提条件
必須サービス:
- Deeplake API サーバーが稼働していること(デフォルト:
https://api.deeplake.ai)
ファイル形式ごとのオプションの Python 依存関係:
- 動画の取り込み:
ffmpeg(sudo apt-get install ffmpeg) - PDF の取り込み:
pymupdf(pip install pymupdf) - サムネイルの生成:
Pillow(pip install Pillow) - COCO 検出形式:
pycocotools、Pillow、numpy(pip install pycocotools Pillow numpy) - LeRobot フレーム形式:
pandas、numpy(pip install pandas numpy)
ファイル形式ごとのオプションの TypeScript 依存関係:
- 動画の取り込み:
ffmpeg(システムバイナリ) - PDF の取り込み:
pdfjs-dist(npm install pdfjs-dist) - サムネイルの生成:
sharp(npm install sharp) - COCO 検出形式:外部依存関係なし(純粋な JS によるマスク描画)
アーキテクチャ
Python: Client(token, workspace_id)
Node.js: ManagedClient({ token, workspaceId })
|-- .ingest(table, data) -> creates PG table via API, opens al://{ws}/{table}
| via deeplake SDK (auto credential rotation)
|-- .create_table(table, schema) -> POST /workspaces/{id}/tables (empty table, no rows)
|-- .query(sql) -> POST /workspaces/{id}/tables/query -> list[dict] / QueryRow[]
|-- .table(table)... -> fluent SQL builder -> list[dict] / QueryRow[]
|-- .create_index(table, col, index_type=) -> CREATE INDEX USING deeplake_index
|-- .drop_index(table, col) -> DROP INDEX (needed to change a column's index type)
|-- .describe_table(table) -> {col: {type, index}} read back from storage
|-- .open_table(table, read_only=) -> deeplake.open[_read_only]("al://{ws}/{table}")
|-- .list_tables() -> GET /workspaces/{id}/tables -> list[str] / string[]
`-- .drop_table(table) -> DELETE /workspaces/{id}/tables/{name}
|
v
REST API -> PostgreSQL + pg_deeplake
- All DB operations go through the REST API (no direct PG connection)
- Dataset access uses al:// paths with automatic credential resolution
- Creds endpoint: GET /api/org/{workspace}/ds/{table}/creds
- Vector similarity: embedding::float4[] <#> query_vec
- BM25 text search: text <#> 'search query'
- Hybrid search: (embedding, text)::deeplake_hybrid_record
クライアントの初期化
Python
from deeplake import Client
client = Client(
token: str = None, # API token (falls back to DEEPLAKE_API_KEY env var)
workspace_id: str = "default", # Target workspace (default: "default")
api_url: str = None, # API URL (default: https://api.deeplake.ai)
org_id: str = None, # Target org UUID. REQUIRED when the token's embedded
# org differs from the org you want to act in (see below).
)
組織をまたぐ呼び出し —
org_id=は指定漏れに注意してください。 API トークンには、複数の組織に所属するユーザーの場合でも、1 つのorg_idクレームが埋め込まれています。SDK が行うすべてのリクエストは組織のスコープに設定されます。org_idを省略すると、そのスコープは指定した組織ではなく、暗黙のうちに トークンに埋め込まれた組織がデフォルトになります。トークンの組織と対象の組織が異なる場合は、必ずorg_id=(Python/JS のキーワード引数)を渡すか、ACTIVELOOP_ORG_IDを設定してください。SDK はこれをX-Activeloop-Org-IdHTTP ヘッダーとして転送します。 サーバーが受け付けるのはこの正確なヘッダーのみです。組織を示す別の名前のヘッダー (例:X-Org-Id)は無視されるため、値が誤っている、または指定されていない場合、エラーが発生しないままトークンの組織にリソースが作成されます。GET /meを使って組織の名前 → UUID を確認してください(トークンがアクセスできる組織 ID が返されます)。認証プロバイダーとorg_idの仕様全体については、reference.md を参照してください。
Node.js / TypeScript
import { ManagedClient, initializeWasm } from 'deeplake';
await initializeWasm();
const client = new ManagedClient({
token: string, // API token (required)
workspaceId?: string, // Target workspace (default: "default")
apiUrl?: string, // API URL (default: https://api.deeplake.ai)
});
トークン: Deeplake プラットフォーム(https://app.deeplake.ai/<org_name>/workspace/<workspace>/apitoken)で API トークンを作成します。このトークンは org_id が埋め込まれた JWT です。DEEPLAKE_API_KEY 環境変数にもフォールバックします(Python のみ)。
バックエンドのエンドポイント: クライアントは初期化時ではなく、データセットを開くたびに C++ バックエンドのエンドポイントを api_url に設定します。これにより、al:// パスの解決(認証情報の取得)がレガシーの controlplane ではなく deeplake-api を経由します。異なる API URL を使用する複数のクライアント間でグローバル状態が上書きされるのを防ぎます。Python:deeplake.client.endpoint = api_url。Node.js:deeplakeSetEndpoint(apiUrl)。
接続のライフサイクル:
# Python: just create and use -- no connection to manage
client = Client()
client.ingest("table", {"path": ["file.txt"]}, schema={"path": "FILE"})
# No close() method -- client is stateless (REST API calls only)
データの取り込み
Python:client.ingest()
result = client.ingest(
table_name: str, # Table name to create (must not already exist)
data: dict[str, list] = None, # Data dict (required unless format= is set).
# {"_huggingface": "name"} -> HuggingFace dataset
# schema has "FILE" cols -> file paths processed
# otherwise -> column data {col: [values]}
*,
format: Format = None, # Format object (subclass of Format) with
# normalize() method. When set, data is ignored.
# e.g. CocoPanoptic(images_dir=..., ...)
schema: dict[str, str] = None, # Schema override {col: type}
# Use "FILE" for columns containing file paths
# See reference.md for all type names
index: list[str] = None, # Columns to create deeplake_index on after ingestion.
# Use for EMBEDDING (vector search) and TEXT (BM25) columns.
on_progress: Callable = None, # Progress callback(rows_written, total)
chunk_size: int = 1000, # Text chunk size (chars)
chunk_overlap: int = 200, # Text chunk overlap (chars)
pdf_dpi: int = 150, # PDF render DPI (higher = sharper but slower)
) -> dict
Node.js:client.ingest()
const result = await client.ingest(
tableName: string, // Table name
data?: Record<string, unknown[]> | null, // Data dict (or null when using format)
options?: {
format?: Format, // Format object with normalize()
schema?: Record<string, string>, // Schema override
index?: string[], // Columns to create deeplake_index on
onProgress?: (processed, total) => void, // Progress callback
chunkSize?: number, // Text chunk size (default 1000)
chunkOverlap?: number, // Text chunk overlap (default 200)
},
): Promise<IngestResult>
テーブルの存在: table_name がすでに存在する場合、ingest() は既存のテーブルにデータを追加します。テーブルを削除して再作成することはありません。既存のテーブルを置き換えるには、先に client.drop_table(table_name) を呼び出してください。PG テーブルのスキーマは、追加する新しいデータと互換性がある必要があります。
戻り値: {"table_name": "videos", "row_count": 150, "dataset_path": "al://workspace_id/videos"}
⚠️
row_countが送信した件数と一致するか、必ず確認してください。ingest()が例外を発生させずに戻ったとしても、行がコミットされた証拠にはなりません。バックエンドの認証情報の更新/プロビジョニング中は、HTTP 層でバッチが受け付けられても、行が 0 件しか書き込まれないことがあります。また、以前のサーバーでは、書き込みに成功していてもrow_count: 0と報告されていました。信頼できる値としてrow_countを使用してください。len(data)と一致しない場合は、書き込まれていない行を再試行してください(取り込みは追加なので、冪等性を保つには決定的な主キーと重複排除、またはINSERT … ON CONFLICT DO NOTHINGを使用してください)。大量のデータを取り込んだ後はSELECT COUNT(*) FROM <table>で確認してください。ただし、反映に遅延がある点に注意してください(クエリ → 書き込み後の読み取りを参照)。
data と format の両方を指定した場合: 両方が指定されていると、format が優先され、data は無視されます。どちらも指定されていない場合は、IngestError が発生します。
サムネイル: フォーマットオブジェクトで image_columns()(pg_schema の型が "IMAGE" の列)が宣言されている場合、4 種類のサイズ(32x32、64x64、128x128、256x256)のサムネイルが自動生成され、共有の thumbnails データセット内の {root_path}/thumbnails に保存されます。Pillow(Python)または sharp(Node.js)が必要です。
ファイルタイプ別のチャンク化戦略
| ファイルタイプ | 拡張子 | 戦略 | 作成される列 |
|---|---|---|---|
| 動画 | .mp4, .mov, .avi, .mkv, .webm | 10 秒のセグメント+サムネイル | id, file_id, chunk_index, start_time, end_time, video_data, thumbnail, text |
| 画像 | .jpg, .jpeg, .png, .gif, .bmp, .webp | 単一チャンク | id, file_id, image, filename, text |
150 DPI でページごと(pdf_dpi で設定可能) | id, file_id, page_index, image, text | ||
| テキスト | .txt, .md, .csv, .json, .xml, .html | 1000 文字のチャンク、200 文字の重複 | id, file_id, chunk_index, text |
| その他 | * | 単一のバイナリチャンク | id, file_id, data, filename |
主な例
# Ingest files (FILE schema)
client.ingest("videos", {"path": ["cam1.mp4", "cam2.mp4"]}, schema={"path": "FILE"})
client.ingest("photos", {"path": ["img1.jpg"]}, schema={"path": "FILE"})
client.ingest("manuals", {"path": ["manual.pdf"]}, schema={"path": "FILE"})
# Ingest structured data (dict = column data, schema inferred)
client.ingest("vectors", {
"text": ["Hello", "Goodbye"],
"embedding": [[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]],
})
# Ingest with explicit schema
client.ingest("data", {"name": ["Alice", "Bob"], "age": [30, 25]},
schema={"name": "TEXT", "age": "INT64"})
# JSONB is a supported schema type — store arbitrary nested JSON per row.
# (Not obvious from the type table; confirmed working end-to-end.)
client.ingest("events", {"id": [1, 2], "payload": [{"k": "v"}, {"n": [1, 2]}]},
schema={"id": "INT64", "payload": "JSONB"})
# Ingest from HuggingFace
client.ingest("mnist", {"_huggingface": "mnist"})
# Ingest with a format object (see formats.md for CocoPanoptic, Coco, LeRobot, custom)
client.ingest("table", format=my_format)
# Ingest with progress callback
def progress(rows_written, total):
print(f"Written {rows_written} rows...")
client.ingest("docs", {"path": pdf_files}, schema={"path": "FILE"}, on_progress=progress)
カスタムフォーマットクラスについては、formats.mdを参照してください。 取り込みの例については、examples.mdを参照してください。
トレーニング/ストリーミング
client.open_table()
管理対象のテーブルを deeplake.Dataset として開き、直接アクセスします。PostgreSQL を介さず、ML フレームワークとの統合機能を内蔵したネイティブのデータセットオブジェクトを返します。
ds = client.open_table(table_name: str, read_only: bool = False) -> deeplake.Dataset
const ds = await client.openTable(tableName: string, readOnly?: boolean);
使用する場面: トレーニングループ、バッチ反復、PyTorch/TensorFlow の DataLoader、非同期プリフェッチ。
読み取りのみを行う場合は、
read_only=Trueを指定してください。 デフォルトでは 読み書き可能として開かれるため、データセットの書き込みハンドルが取得され、 意図せず残ったappend/commitによって、確認だけするつもりだったテーブルが 変更される可能性があります。read_only=Trueを指定すると、変更メソッドが例外を 発生させるReadOnlyDatasetが返されます。読み取り、クエリ、summary()、バッチ 反復、データローダーは、これまでどおり動作します。
# Inspect without taking write access
ds = client.open_table("videos", read_only=True)
ds.summary()
# Batch iteration (training reads only — open read-only)
ds = client.open_table("videos", read_only=True)
for batch in ds.batches(32):
train(batch)
# PyTorch DataLoader
from torch.utils.data import DataLoader
ds = client.open_table("training_data", read_only=True)
loader = DataLoader(ds.pytorch(), batch_size=32, shuffle=True, num_workers=4)
# TensorFlow tf.data.Dataset
ds = client.open_table("training_data", read_only=True)
tf_ds = ds.tensorflow().batch(32).prefetch(tf.data.AUTOTUNE)
# Writing still needs the default read/write handle
ds = client.open_table("training_data")
ds.append({"id": ["x"]})
ds.commit()
Node.js に関する注意:
openTable(name, true)にはdeeplake_open_read_onlyバインディングを含む WASM ビルドが必要で、describeTable()にはDataset.summary()を含むビルドが必要です。古いバンドルでは、 不足しているバインディング名を示す明確なエラーが発生します。WASM モジュールを 再ビルドする(python3 scripts/build_wasm_node.py dev)か、両方が以前から提供されている Python 側を使用してください。
クエリ
Fluent Query API(推奨)
client.table(table) は、チェーン可能な ManagedQueryBuilder を返します。
# Python: supports both .execute() and () to run the query
results = (
client.table("videos")
.select("id", "text", "start_time")
.where("file_id = $1", "abc123")
.where("start_time > $2", 60)
.order_by("start_time ASC")
.limit(10)
.offset(0)
)() # or .execute()
// Node.js: use .execute() only (no () shorthand)
// (assumes initializeWasm() already called at startup)
const results = await client.table("videos")
.select("id", "text", "start_time")
.where("file_id = $1", "abc123")
.where("start_time > $2", 60)
.orderBy("start_time ASC")
.limit(10)
.offset(0)
.execute();
| メソッド | Python | Node.js | 説明 |
|---|---|---|---|
.select(*cols) | .select("id", "t") | .select("id", "t") | 列を設定します(デフォルトは *) |
.where(cond, *params) | .where("id=$1","x") | .where("id=$1","x") | WHERE 条件を追加します(複数指定時は AND) |
.order_by(clause) | .order_by("col") | .orderBy("col") | ORDER BY を追加します |
.limit(n) | .limit(10) | .limit(10) | LIMIT を設定します |
.offset(n) | .offset(20) | .offset(20) | OFFSET を設定します |
| クエリを実行 | .execute() または () | .execute() | 実行して結果を返します |
.where() のパラメーターの仕組み: .where("col = $N", value) を呼び出すたびに AND 条件が追加されます。$1、$2 などのプレースホルダーには追加の引数が順番に割り当てられ、すべての .where() 呼び出しを通して連番になります。
生 SQL:client.query()
# Python
rows = client.query(
sql: str,
params: tuple = None,
timeout: int = 60, # HTTP timeout in seconds (increase for slow queries)
) -> list[dict]
# Examples
rows = client.query("SELECT * FROM videos LIMIT 10")
rows = client.query("SELECT * FROM documents WHERE file_id = $1", ("abc123",))
rows = client.query("SELECT COUNT(*) FROM big_table", timeout=300) # 5-minute timeout
// Node.js
const rows = await client.query(
sql: string,
params?: unknown[],
options?: { timeoutMs?: number }, // default 60000 (60s)
) -> Promise<QueryRow[]>
// Examples
const rows = await client.query("SELECT * FROM videos LIMIT 10");
const rows = await client.query("SELECT * FROM documents WHERE file_id = $1", ["abc123"]);
const rows = await client.query("SELECT COUNT(*) FROM big", undefined, { timeoutMs: 300_000 });
クエリは POST /workspaces/{id}/tables/query を介して API に送信されます。パラメーター化クエリには $1、$2、...を使用してください。
タイムアウト: デフォルトのクエリタイムアウトは 60 秒です。長時間実行されるクエリ(大規模な集計、インデックスの構築)では、
timeout/timeoutMsパラメーターで値を大きくしてください。デフォルト以外のタイムアウトはtimeout_msとしてバックエンドに転送されるため、サーバー側でも期限を適用できます。
pg_deeplake の SQL 機能(ベクトル検索、BM25、ハイブリッド検索、インデックス)については、reference.md を参照してください。
書き込み後の読み取り:取り込みからクエリまでの可視化の遅延
ingest()/INSERT が成功しても、直後の読み取りにすぐ反映されるとは限りません。書き込みはオブジェクトストレージに非同期でフラッシュされるため、コミットの数ミリ秒後に実行した COUNT(*) が、古い件数(新しいテーブルでは多くの場合 0)を返すことがあります。これはデータ損失ではなく、タイミングによる遅延です。取り込みに続けてクエリを実行する場合は、次のいずれかを行ってください。
SELECT COUNT(*) FROM <table>をポーリングし、想定件数に達するまで待ちます(数秒、実測では約 5 秒かかることがあります)。または- サイドプロセスが同じデータセットパスを範囲外で変更し、その後の読み取りで
schema drift/古い結果が発生した場合は、キャッシュされたスナップショットを破棄します。
SELECT deeplake_resync_table_pointer('my_table'::regclass); -- re-open at HEAD
SELECT COUNT(*) FROM my_table; -- now current
deeplake_resync_table_pointer(pg_deeplake 1.13 以降)は、未フラッシュの DML がある場合は実行されません。先に deeplake_flush_table('my_table'::regclass) を呼び出してください。詳細は reference.md を参照してください。
SQL 方言 — Postgres ワイヤープロトコル、DuckDB による実行
deeplake テーブルへのクエリは PostgreSQL として解析されますが、内部では DuckDB エンジンによって実行されます。そのため、2 つの方言は完全には一致せず、その違いがエラーメッセージに現れることがあります。
jsonb関数: DuckDB が公開するのはjson_*であり、PostgreSQL のjsonb_*エイリアスではありません。jsonb_array_length(col)は失敗します(「json_array_length のことですか」)。json_array_length(jsonb_col)も失敗する場合があります。確実な方法はjson_array_length(col::json)です。json_*の関数名を優先し、jsonbをjsonにキャストしてください。- JSON アクセス演算子: PostgreSQL の
->/->>'key'演算子は動作しますが、内部では DuckDB のパス構文('$.key')にマッピングされます。エラーに表示されるのはこの構文です。json_extract(col, '$.key')で抽出すれば、予期しない動作を避けられます。 - DDL の制限: 列の型をインプレースで変更することはサポートされていません。
ALTER TABLE … ALTER COLUMN … TYPE …は「VACUUM FULL is not supported for deeplake tables」というエラーで失敗します。列の型を変更するには、目的のスキーマで新しいテーブルを作成し、データをコピーしてください(INSERT INTO new SELECT … FROM old)。
テーブル管理
# Python
tables = client.list_tables() -> list[str]
client.drop_table(table_name: str, if_exists: bool = True) -> None
client.create_table(table_name: str, schema: dict, *,
index=None, if_not_exists: bool = True) -> dict
client.create_index(table_name: str, column: str, *,
index_type: str = None, dimension: int = None) -> None
client.drop_index(table_name: str, column: str, if_exists: bool = True) -> None
client.describe_table(table_name: str) -> dict
// Node.js
const tables = await client.listTables();
await client.dropTable(tableName: string, ifExists?: boolean); // default true
await client.createTable(tableName: string, schema: SchemaMap,
options?: { index?: IndexSpec, ifNotExists?: boolean });
await client.createIndex(tableName: string, column: string,
options?: { indexType?: string, dimension?: number });
await client.dropIndex(tableName: string, column: string, ifExists?: boolean);
await client.describeTable(tableName: string);
テーブルの作成
ingest() は、行を書き込む副作用としてテーブルを作成します。create_table()/createTable() は、明示的なスキーマを持つ空のテーブルを作成します。データが入る前にテーブルを用意しておく必要がある場合に使用します。たとえば、既存のデータセットを模したスケルトンの作成、INSERT INTO … SELECT の対象となるテーブルの準備、値からの推論では特定できないドメイン型の事前宣言に使えます。
result = client.create_table("docs", {
"id": "TEXT",
"chunk_id": "TEXT",
"created_at": "INT64",
"embedding": "EMBEDDING(1536)",
}, index={
"id": "inverted_index",
"chunk_id": "inverted_index",
"embedding": "clustered",
})
# {"table_name": "docs", "created": True, "dataset_path": "al://ws/docs"}
⚠️ 単独の
EMBEDDINGではなく、EMBEDDING(dim)を記述してください。 単独のEMBEDDINGはパラメーターなしのfloat4[]にマッピングされ、pg_deeplake では 可変長 の浮動小数点配列として保存されます。embedding(dim, float32)列にはなりません。空のスケルトンには次元を推論できる行がないため、後からcreate_indexを実行しても利用できる情報がありません(dimension=を手動で渡す必要があります)。EMBEDDING(1536)を指定すると、列はembedding(1536, clustered)として返され、実際のベクトルデータセットと一致します。マップで認識されない型名は、現在 PostgreSQL にそのまま渡されます。そのため、
SMALLINT、TEXT[]、LINK(IMAGE)はすべて使用でき、タイプミスはTEXT列に黙って変換されるのではなく、サーバーエラーとして通知されます。
EMBEDDING(N)にはclusteredインデックスがすでに含まれています。 列を宣言するだけで十分です。create_indexを呼び出す前でも、describe_tableはindex=clusteredとともにembedding(N, clustered)を報告します。そのため、index={"col": "clustered"}を渡すのは冗長です(問題はなく、同じ型なので何も行われません)が、そのような列に別の型を要求すると失敗します。Conflicting index types for column 'emb': existing index type 'clustered'
clustered_quantizedインデックスを作成するには、列を単独の"EMBEDDING"(インデックスを持たない通常のfloat4[])として宣言し、インデックス作成時に次元を渡してください。client.create_table("vecs", {"emb": "EMBEDDING"}) client.create_index("vecs", "emb", index_type="clustered_quantized", dimension=1536)
テーブルがすでに存在する場合、create_table は created=False を返します(代わりにエラーにするには、if_not_exists=False を渡してください)。ingest とは異なり、ここでインデックス作成に失敗すると、例外が発生します。保護すべきコミット済みデータはありません。
インデックスの作成
create_index()/createIndex() は、列に deeplake_index を作成します。次の用途に使用します。
- EMBEDDING 列 —
<#>によるベクトルコサイン類似度検索を有効にします - TEXT 列 — BM25 ランキングまたはキーワードの
CONTAINS検索を有効にします
このメソッドは CREATE INDEX IF NOT EXISTS ... USING deeplake_index (column) WITH (index_type = '…') を実行します。
インデックスの種類 — クローンではデフォルトが通常適切でない理由
| 列の種類 | 受け付ける index_type | 省略時のデフォルト |
|---|---|---|
| テキスト | exact_text, bm25, inverted_index | exact_text |
| 埋め込み(1-D) | clustered, clustered_quantized | clustered |
| 埋め込み(2-D) | pooled_quantized | pooled_quantized |
| 数値 | inverted_index | inverted_index |
| JSON/dict | inverted_index | inverted_index |
| 任意 | unique | — |
受け付けるエイリアス:inverted → inverted_index、exact → exact_text、
quantized/binary_quantized → clustered_quantized。
⚠️ テキストのデフォルトは、実際のデータセットの多くに適合しません。 引数なしの
create_index(table, "text")はexact_textを構築します。これはcol = 'x'の等価性検索にしか対応しません。ソースデータセットでは通常、inverted_index(キーワードのCONTAINS) またはbm25(全文検索のランキング)が使われています。データセットのインデックスを複製するには、 種類を明示して指定してください。推測するのではなく、describe_table()で確認してください。
# Python — standalone
client.create_index("documents", "text", index_type="bm25") # full-text ranking
client.create_index("documents", "keywords", index_type="inverted_index")
client.create_index("embeddings", "embedding", index_type="clustered")
# A clustered index over a bare float4[] column that has no rows yet needs the
# dimension supplied — there is nothing to infer it from.
client.create_index("skeleton", "embedding",
index_type="clustered", dimension=1536)
# Python — during ingestion (creates indexes after data is committed)
client.ingest("search_index", {
"text": documents,
"embedding": embeddings,
}, index={"text": "bm25", "embedding": "clustered"})
// Node.js — standalone
await client.createIndex("documents", "text", { indexType: "bm25" });
await client.createIndex("embeddings", "embedding", { indexType: "clustered" });
await client.createIndex("skeleton", "embedding",
{ indexType: "clustered", dimension: 1536 });
// Node.js — during ingestion
await client.ingest("search_index", {
text: documents,
embedding: embeddings,
}, { index: { text: "bm25", embedding: "clustered" } });
index= 引数は、ingest() と create_table() の両方で、次の3つの形式を受け付けます。
| 形式 | 意味 |
|---|---|
["embedding", "text"] | 列の種類ごとのデフォルトのインデックスの種類 |
{"embedding": "clustered", "text": "bm25"} | 列ごとに種類を明示 |
{"embedding": {"index_type": "clustered", "dimension": 1536}} | 詳細な制御 |
既存のインデックスの種類を変更する
pg_deeplake では、列ごとに1つのインデックスのみが許可されます。すでにインデックスが付与されている列に対する
CREATE INDEX IF NOT EXISTS は、pg_deeplake が認識する前に PostgreSQL によってスキップされます。そのため、
index_type を修正して再実行しても、何も起きずに終わります。クライアントはこれを検出し、代わりにエラーを発生させます。
client.create_index("docs", "text", index_type="bm25")
# TableError: Column 'text' of table 'docs' already has a 'exact_text' index
# (idx_docs_text), which does not match the requested 'bm25'. CREATE INDEX
# would skip it silently. Resolution: client.drop_index('docs', 'text') first.
client.drop_index("docs", "text")
client.create_index("docs", "text", index_type="bm25") # now takes effect
同じ種類を再度リクエストした場合は何も行われないため、create_table(..., index=...) は安全に再実行できます。
⚠️ 現時点では、マネージドサービスで種類を変更しても確実に反映されるとは限りません。
DROP INDEXは PostgreSQL のカタログエントリをすぐに削除しますが、各 バックエンドポッドは deeplake インデックスのコピーをそれぞれ保持しており、独自の スケジュールで削除します。その直後に新しい種類を指定してcreate_indexを実行すると、 変更が反映されていないポッドによって「すでに存在する」または種類の競合として 拒否されることがあり、クライアントの約10秒の再試行枠を超えて続くこともよくあります。api-beta での 実測では、成功するのは約5回に1回です。クライアントは短時間で解消するケースには対応します。試行回数を使い切った場合は、作成していない インデックスを作成済みと報告するのではなく、エラーを発生させます。そのため、実際にはインデックスが付与されていないのに、 付与済みだと思い込むことはありません。この問題が発生した場合は、待ってから再試行するか、 最初から希望するインデックスの種類を指定してテーブルを作成してください。カタログではなくストレージを読み取る
describe_table()で確認してください。
テーブルの実際のスキーマとインデックスを確認する
describe_table() はテーブルを読み取り専用で開き、作成時に指定された内容ではなく、実際にストレージに保存されている内容を報告します。構築済みのインデックスタイプは、Python/JS API のほかの場所では公開されていません(Dataset.summary() が出力する型文字列に埋め込まれています)。そのため、これを確認できる唯一の方法です。
client.describe_table("embedding_noquantized")
# {'chunk_id': {'type': 'text (compression=lz4)', 'index': 'inverted_index'},
# 'created_at': {'type': 'int64', 'index': None},
# 'embedding': {'type': 'embedding(1536, clustered)', 'index': 'clustered'},
# 'id': {'type': 'text (compression=lz4)', 'index': 'inverted_index'}}
これをそのまま create_table に渡すと、スキーマを複製できます。完全なひな形のレシピについては、examples.md を参照してください。
注意点: 複製されるのはカラム型、次元、インデックスタイプであり、チャンク圧縮は複製されません。pg_deeplake は PG の
TEXTカラムをtext(compression=null)に固定するため、SDK で作成されたソースがcompression=lz4と表示される場合、ここは異なります。これはストレージサイズにのみ影響し、セマンティクスとクエリには影響しません。
注: 新しく作成されたテーブルがすべてのバックエンドポッドで参照可能になるまで、少し時間がかかります。
create_indexはこの時間差を自動的に吸収するため(「does not have DeepLake access method」/「does not exist」に対する上限付き再試行)、create_table(..., index=...)を一度に安全に呼び出せます。
ワークスペース管理
ワークスペースは REST API 経由で作成します。SDK クライアントには組み込みの createWorkspace() メソッドがないため、apiRequest を直接使用してください。
重要: ワークスペースの作成時には id フィールドが必須です。省略するとエラーが返されます。
⚠️ ワークスペースはどの組織に作成されますか?
POST /workspacesは、リクエストのスコープとなっている組織にワークスペースを作成します。このスコープはX-Activeloop-Org-Idヘッダーで指定され、このヘッダーのみが使われます。複数の組織に所属していて、組織ヘッダーを指定しない場合(またはX-Org-Idのような誤ったヘッダーを指定した場合)、意図した組織ではなく、トークンに埋め込まれた組織にワークスペースが通知なしで作成されます。エラーは返されません。対象の組織がトークンの組織と異なる場合は、必ずX-Activeloop-Org-Id: <target-org-uuid>を設定するか(またはorg_id=を指定してクライアントを作成してください。これにより自動的にヘッダーが追加されます)、その後、データを取り込む前にGET /workspaces(各行のorg_idフィールド)で確認してください。
// Node.js — create workspace via API
import { apiRequest, extractOrgId } from 'deeplake';
// extractOrgId reads the token's embedded org. Pass a DIFFERENT org UUID here to
// target another org — apiRequest sends it as X-Activeloop-Org-Id.
const orgId = targetOrgId ?? extractOrgId(token);
await apiRequest(apiUrl, token, orgId, {
method: 'POST',
path: '/workspaces',
body: { id: 'my-workspace', name: 'My Workspace' },
timeoutMs: 30_000,
});
# Python — create workspace via API
import requests
resp = requests.post(
f"{api_url}/workspaces",
headers={"Authorization": f"Bearer {token}"},
json={"id": "my-workspace", "name": "My Workspace"},
)
resp.raise_for_status()
ワークスペースを一覧表示する:
// Node.js
const resp = await apiRequest(apiUrl, token, orgId, {
method: 'GET',
path: '/workspaces',
});
// resp.data = [{ id, org_id, name, type, created_at }, ...]
| フィールド | 必須 | 説明 |
|---|---|---|
id | はい | ワークスペース識別子(API パスと al:// URL で使用) |
name | いいえ | 表示名(省略時は id が既定値) |
注:
idを省略すると、HTTP 400 Bad Request と「workspace ID is required」というメッセージが返されます。
エラー処理
Python と Node.js は、同じエラー階層を共有します。
ManagedServiceError # Base class for all errors
├── AuthError # Token invalid/expired
│ └── TokenError # Token parsing failed
├── CredentialsError # DB credentials fetch failed
├── IngestError # File ingestion failed
├── TableError # Table operation failed
└── WorkspaceError # Workspace not found or inaccessible
# Python imports
from deeplake.managed import (
ManagedServiceError, AuthError, CredentialsError,
IngestError, TableError, TokenError, WorkspaceError,
)
// Node.js imports
import {
ManagedServiceError, AuthError, CredentialsError,
IngestError, TableError, TokenError, WorkspaceError,
} from 'deeplake';
| エラー | 原因 | 解決策 |
|---|---|---|
AuthError: Token required | トークンが指定されていない | Client() に token= を渡すか、環境変数 DEEPLAKE_API_KEY を設定してください |
AuthError: Token does not contain org_id | トークンに OrgID クレームがない | トークンに OrgID クレームがあること、または API /me にアクセスできることを確認してください |
IngestError: File not found | ファイルパスが無効 | 指定したパスにファイルが存在することを確認してください |
TableError: table creation failed | API によるテーブル作成に失敗 | API サーバーが稼働中で、ワークスペースにアクセスできることを確認してください |
WorkspaceError: No storage path | API からパスが返されなかった | ワークスペースが存在し、ストレージが設定されていることを確認してください |
トラブルシューティングの詳細については、reference.md を参照してください。
信頼性と再試行
マネージドバックエンドは、共有型の自動スケーリングプールです。個々のポッドは再起動し、負荷に応じてスケールアップし、ストレージ認証情報を更新します。そのため、一時的なエラーは通常発生するものであり、堅牢なクライアントには再試行が必要です。一括コピーや ETL のループには、これらの動作を組み込んでください。
一時的な HTTP ステータスをバックオフ付きで再試行する
| ステータス | 意味 | クライアントのアクション |
|---|---|---|
503(多くの場合 Retry-After を伴う) | バックエンドのスケーリング中/高負荷/接続失敗 — クエリは実行されていません | Retry-After に従い(デフォルトは約2秒)、指数バックオフで再試行します |
| 504 | クエリが期限を超過しました | 再試行するか、timeout を延長するか、LIMIT を追加します |
| 429 | レート制限に達しました | Retry-After に従います |
| クエリに対する 502 / 500 | まれにしか発生しないはずです。一時的なエラーとして扱い、上限を設けて再試行します | バックオフ付きで再試行し、解消しない場合はアラートを出します |
読み取りは常に安全に再試行できます。書き込みは、書き込みが冪等な場合に限り再試行してください(決定的な主キーと ON CONFLICT DO NOTHING の組み合わせ、または重複排除処理)。503 は書き込みが実行されなかったことを意味しますが、サーバーによるコミット後に接続が切断された場合は結果が不明確になるため、冪等性をデフォルトとするのが安全です。
⚠️ サイレントな切り捨て:空のページが必ずしもデータの終わりとは限りません
ページネーションを行うクライアント(LIMIT/OFFSET またはキーセットのループ)で最も危険な障害モードは、バックエンドの認証情報更新中に、まだデータが残っているにもかかわらず、ページが行数0の HTTP 200を返すことです。「ページが空 ⇒ 完了」と判断する単純なループでは、気づかないうちにデータが切り捨てられ、たとえば24万9千行中13万7千行で処理を停止して成功と報告してしまいます。次の方法で防いでください。
- 1ページが空だっただけで完了と判断しないでください。 まず総数を照合し(
SELECT COUNT(*))、その数の行を読み取るまでページネーションを続けてください。 OFFSETよりもキーセットページネーション(WHERE id > $last ORDER BY id LIMIT n)を優先し、最後のキーが進んでいることを確認してください。- ストリームの途中で予期せずページが空になった場合、処理を完了と判断する前に、短いバックオフの後でそのページを再リクエストしてください。データの終端であればページは空のままですが、認証情報の更新による一時的な問題なら、再試行時にデータが取得できます。
- コピー後に
rows_copied == COUNT(*)を検証し、不一致があれば明確に失敗させてください。
取り込み後にコミット済み件数を確認する
取り込みを参照してください。ingest() が戻ったことは、コミットされた証拠にはなりません。返された row_count を送信した件数と比較し、一括ロードの結果は最終的な COUNT(*) と照合してください(上記の可視性の遅延を考慮してください)。
エージェントの判断ツリー
判断:クライアントの初期化方法
Need to create a Client
|
|-- Python?
| |-- DEEPLAKE_API_KEY env var is set?
| | `-- client = Client() # defaults: token from env, workspace="default"
| |-- Have explicit token?
| | `-- client = Client(token="dl_xxx") # workspace defaults to "default"
| |-- Need specific workspace?
| | `-- client = Client(workspace_id="my-ws") # token from env
| `-- Need custom API URL?
| `-- client = Client(api_url="http://custom:8080")
|
`-- Node.js?
`-- import { ManagedClient, initializeWasm } from 'deeplake';
await initializeWasm();
const client = new ManagedClient({
token: process.env.DEEPLAKE_API_KEY!,
workspaceId: "my-ws", // optional, default "default"
apiUrl: "http://custom:8080", // optional
});
判断:データの取り込み方法
User wants to ingest data
|
|-- Is it local files? -> use FILE schema
| |-- Python:
| | `-- client.ingest("table", {"path": ["f1.mp4", "f2.mp4"]},
| | schema={"path": "FILE"})
| `-- Node.js:
| `-- await client.ingest("table", { path: ["f1.mp4"] },
| { schema: { path: "FILE" } })
|
|-- Is it structured data (dict/lists)? -> pass a dict directly
| |-- Python:
| | `-- client.ingest("table", {"col1": [...], "col2": [...]})
| `-- Node.js:
| `-- await client.ingest("table", { col1: [...], col2: [...] })
|
|-- Is it a HuggingFace dataset? -> use _huggingface key
| `-- client.ingest("table", {"_huggingface": "dataset_name"})
|
|-- Is it a LeRobot robotics dataset? -> 3-table design (tasks + frames + episodes)
| |-- from deeplake.managed.formats import LeRobotTasks, LeRobotFrames, LeRobotEpisodes
| |-- client.ingest("tasks", format=LeRobotTasks(dataset_dir))
| |-- client.ingest("frames", format=LeRobotFrames(dataset_dir, chunk_start=0, chunk_end=3))
| `-- client.ingest("episodes", format=LeRobotEpisodes(dataset_dir, chunk_start=0, chunk_end=3))
| Note: chunk_end is inclusive. Episodes requires git lfs. See examples.md Workflow 7.
|
|-- Is it a domain-specific format (COCO, etc.)? -> use format object
| |-- Python: client.ingest("table", format=my_format)
| `-- Node.js: await client.ingest("table", null, { format: myFormat })
| See formats.md for built-in formats: CocoPanoptic, Coco, LeRobot, custom
|
|-- Need custom chunking for text?
| `-- client.ingest("table", {"path": ["doc.txt"]},
| schema={"path": "FILE"},
| chunk_size=500, chunk_overlap=100)
|
`-- Need explicit schema?
| `-- client.ingest("table", {...}, schema={
| "name": "TEXT",
| "count": "INT64",
| "vector": "EMBEDDING",
| })
|
|
|-- Need the table to exist BEFORE any data? (skeleton, INSERT…SELECT target)
| `-- client.create_table("table", {"id": "TEXT", "embedding": "EMBEDDING(1536)"},
| index={"id": "inverted_index", "embedding": "clustered"})
| Use EMBEDDING(dim), not bare EMBEDDING — an empty table has no rows to
| infer the dimension from.
|
`-- Need indexes for search performance?
`-- client.ingest("table", {...}, index=["embedding", "text"])
Explicit types: index={"text": "bm25", "embedding": "clustered"}
Or standalone: client.create_index("table", "embedding",
index_type="clustered")
The text default is exact_text (equality only) — pass bm25 or
inverted_index if that is what you actually want.
判断:別のデータセットのスキーマを再現する方法
Need a table with the same columns AND indexes as an existing dataset
|
|-- 1. Read the source (read-only — never take write access to inspect)
| src = client.describe_table("source_table")
| -> {col: {"type": "embedding(1536, clustered)", "index": "clustered"}}
|
|-- 2. Translate deeplake types -> schema types
| "embedding(1536, ...)" -> "EMBEDDING(1536)" # keep the dimension!
| "text (compression=…)" -> "TEXT"
| "int64" -> "INT64"
|
|-- 3. Carry each column's index type across verbatim
| index = {c: i["index"] for c, i in src.items() if i["index"]}
|
`-- 4. client.create_table("skeleton", schema, index=index)
Verify: client.describe_table("skeleton") == src
See examples.md Workflow 10 for the complete script.
判断:データのクエリ方法
User wants to query data
|
|-- Simple SELECT (small result)?
| |-- Python fluent: client.table("table").select("id", "text").limit(100)()
| |-- Python raw: client.query("SELECT * FROM table LIMIT 100")
| |-- Node fluent: await client.table("table").select("id", "text").limit(100).execute()
| `-- Node raw: await client.query("SELECT * FROM table LIMIT 100")
|
|-- Large result set (streaming)?
| `-- Use client.open_table("table", read_only=True) for direct dataset access
| with batch iteration, PyTorch/TF DataLoaders, etc.
|
|-- Need semantic/vector search?
| `-- from deeplake.managed import vector_literal
| client.query(f"""
| SELECT *, embedding::float4[] <#> {vector_literal(query_embedding)} AS score
| FROM table ORDER BY score DESC LIMIT 10
| """)
| Through client.query() a vector CANNOT be passed as $1 -- the REST API
| serializes it to a string that arrives at the DuckDB executor as
| VARCHAR. Inline it. Scalars/text as $1 are fine. (On a direct psql /
| asyncpg / psycopg connection $1::float4[] binds a real array and works.)
|
|-- Need text search?
| `-- client.query("""
| SELECT * FROM table
| WHERE text @> $1
| """, ("keyword",))
|
`-- Need hybrid search (vector + text)?
`-- client.query(f"""
SELECT *, (embedding, text)::deeplake_hybrid_record <#>
deeplake_hybrid_record({vector_literal(query_emb)}, $1, 0.7, 0.3) AS score
FROM table ORDER BY score DESC LIMIT 10
""", ("search text",))
Vector inlined; the text argument can stay a parameter.
判断:ユーザーがデータを使った学習を希望している場合
User wants to train / iterate over data
|
|-- Fast native batch iteration (RECOMMENDED for large datasets)?
| |-- ds = client.open_table("table", read_only=True)
| | for batch in ds.batches(256): # dict of numpy arrays
| | states = torch.tensor(np.stack([batch[c] for c in cols], axis=1))
| |-- For column subsets, use query first:
| | view = ds.query("SELECT col1, col2 WHERE episode_index < 100")
| ` for batch in view.batches(256): ...
|
|-- Need PyTorch DataLoader (small datasets or need shuffle)?
| `-- ds = client.open_table("table", read_only=True)
| loader = DataLoader(ds.pytorch(), batch_size=32, shuffle=True)
| NOTE: Slower on large remote datasets — prefer ds.batches() above
|
|-- Need TensorFlow tf.data?
| `-- ds = client.open_table("table", read_only=True)
| tf_ds = ds.tensorflow().batch(32).prefetch(AUTOTUNE)
|
`-- Training on LeRobot data?
|-- Behavior cloning (state->action):
| ds = client.open_table("droid_frames", read_only=True)
| view = ds.query("SELECT state_x, ..., action_x, ... WHERE episode_index < 100")
| for batch in view.batches(256):
| states = torch.tensor(np.stack([batch[c] for c in STATE_COLS], axis=1))
| actions = torch.tensor(np.stack([batch[c] for c in ACTION_COLS], axis=1))
| # train(model, states, actions)
|
`-- Video-conditioned training:
ds = client.open_table("droid_episodes", read_only=True)
# Access video bytes via ds[i]["exterior_1_video"], etc.
判断:エラーからの復旧方法
Operation failed with error
|
|-- AuthError?
| |-- "Token required" -> Set DEEPLAKE_API_KEY env var or pass token= to Client()
| |-- "Token does not contain org_id" -> Ensure token has OrgID claim
| `-- "Token expired" -> Get new token
|
|-- IngestError?
| |-- "data must be a dict" -> Pass a dict, not list/str/int
| |-- "data must not be empty" -> Dict must have at least one key
| |-- "File not found" -> Check file path exists
| |-- "ffmpeg not found" -> Install ffmpeg for video processing
| `-- "fitz not found" / "pdfjs-dist not found" -> Install pymupdf (Python) or pdfjs-dist (Node.js)
|
|-- TableError?
| |-- "create_deeplake_table failed" -> Check pg_deeplake extension
| |-- "Table already exists" -> Use drop_table() first or different name
| |-- "Index creation failed" -> Check column exists and is EMBEDDING or TEXT type
| |-- "already has index ... does not match the requested" ->
| | One index per column. client.drop_index(table, col), then recreate.
| |-- "Invalid index type 'X' for text column" ->
| | Use exact_text | bm25 | inverted_index (embeddings: clustered |
| | clustered_quantized | pooled_quantized)
| |-- "does not have DeepLake access method" right after create_table ->
| | Backend pod hasn't caught up. create_index already retries; if you
| | hit it elsewhere, wait a few seconds and retry.
| |-- "not float32 array, hence not supported yet for indexing" ->
| | Column is not an embedding. Declare it EMBEDDING(dim), or pass
| | dimension= when indexing a bare float4[] column.
| `-- "Query timed out" -> Increase timeout: client.query(sql, timeout=300)
|
|-- ValueError: "Unknown index_type"?
| `-- Valid: inverted_index, bm25, exact_text, clustered,
| clustered_quantized, pooled_quantized, unique
|
|-- Skeleton table's column came back as TEXT instead of a vector?
| `-- Schema said "EMBEDDING" (no dimension). Use "EMBEDDING(1536)".
|
|-- ReadOnlyDatasetModificationError / AttributeError on append?
| `-- The handle came from open_table(..., read_only=True). Reopen without it.
|
|-- WorkspaceError / "workspace ID is required"?
| `-- POST /workspaces requires the "id" field in the request body.
| Use: { id: "my-ws", name: "My Workspace" }
|
|-- "Not found: /workspaces/.../tables"?
| `-- Workspace must exist before ingest(). Create it via the API or UI first.
|
|-- Tables created via raw SQL not visible to ingest()?
| `-- Raw SQL tables (CREATE TABLE ... USING deeplake) are not registered with
| the managed API. Use client.ingest() to create tables. Use client.query()
| for raw SQL operations on manually-created tables.
|
|-- Thumbnail generation failed? (logged as warning, non-fatal)
| |-- Python: Install Pillow (`pip install Pillow`)
| `-- Node.js: Install sharp (`npm install sharp`)
|
`-- ManagedServiceError?
`-- Check API server is running at the configured api_url
関連ファイル
- reference.md -- pg_deeplake SQL リファレンス(ベクトル検索、BM25、ハイブリッド検索、インデックス)、データ型、LINK 型とラウンドトリップ、既存の SDK データセットのアタッチ(SECURITY LABEL physical_name と
deeplake_resync_table_pointer)、管理対象の認証情報(Azure/GCS)とdeeplake_set_creds_key()、制限、パフォーマンスのチューニング、トラブルシューティング - examples.md -- エンドツーエンドのワークフロー例と詳細な取り込み例
- formats.md -- Format 基底クラス、カスタム Format クラス、normalize()/schema()/image_columns() のルール