2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Codeはなぜベクトル検索を捨てたのか — Embeddingの仕組みから理解する

2
Posted at

はじめに

AnthropicのCLIツール「Claude Code」は、初期バージョンでRAGとローカルベクトルDBを使っていた。しかし、現在のClaude Codeにベクトル検索は搭載されていない。捨てたのだ。

開発者のBoris Chernyはこう語っている:

初期版ではRAGとローカルベクトルDBを使用していたが、agentic searchの方が概ね優れていることが判明した。シンプルでセキュリティ・プライバシー面でも問題がない。

代わりに採用されたのは、Glob(ファイル名検索)、Grep(テキスト検索)、Read(ファイル読み取り)という、一見レガシーなツール群。ただし、それをLLMが自律的に組み合わせる「Agentic RAG」というアプローチだ。

なぜベクトル検索では駄目だったのか? そもそもベクトル検索とは何で、Embeddingとはどう違うのか? Agentic RAGとは何か?

この記事では、Embeddingの仕組みを基礎から解説し、その上で**「ベクトル検索 vs Agentic RAG」の判断軸**を示す。


目次

  1. 前提知識 — ベクトルと次元
  2. ベクトル化・ベクトル検索・RAG — 3つの違い
  3. Embeddingの仕組み — テキストがベクトルになるまで
  4. 学習方法 — モデルはどう訓練されるか
  5. ベクトル空間と類似度
  6. ベクトル検索の実際 — DB・チャンキング・インデックス
  7. Agentic RAG — ベクトル検索を超えるアプローチ
  8. どちらを選ぶべきか — 判断フレームワーク
  9. まとめ

1. 前提知識 — ベクトルと次元

Embeddingの話に入る前に、「そもそもコンピュータは言葉をどう扱うのか」を押さえておこう。

コンピュータは数字しか分からない

コンピュータの中身は0と1だ。文字列 "犬" も内部的にはUTF-8で 0xE7 0x8A 0xAC(3バイトの数値)として保存されている。

しかしこの数値は文字のIDに過ぎない。「犬」が「猫」に似ているとか、「経済学」とは無関係だとか、そういった意味は一切含まれていない。

文字コード(UTF-8):
  "犬" → 0xE78AAC
  "猫" → 0xE78CAB
  "犬" と "猫" の数値は近い? → たまたま近いだけ。意味的根拠はない

  "dog" → 0x646F67
  "犬" → 0xE78AAC
  "dog" と "犬" の数値は近い? → まったく違う。しかし意味は同じ

問題: 文字コードでは意味を扱えない。「意味を反映した数値表現」が必要になる。

ベクトルとは何か

ベクトルとは**数値の並び(配列)**だ。プログラマなら float[]list[float] と思えばいい。

# 2次元ベクトル(地図上の座標のようなもの)
position = [3.0, 4.0]

# 768次元ベクトル(Embeddingの実際の出力)
embedding = [0.21, -0.53, 0.82, ..., 0.31]  # 768個のfloat

なぜ「ベクトル」と呼ぶのか?数学的に、ベクトルは空間上の点、あるいは原点からの矢印を表す。2次元ベクトル [3, 4] はXY平面上の点 (3, 4) だ。これが768次元になっても本質は同じ——768次元空間上の1つの点を指す。

次元とは何か

「768次元」と聞くと構えてしまうが、原理は単純だ。

1次元: 数直線上の位置       → [5.0]               → 1つの数値で表せる
2次元: 平面上の位置         → [3.0, 4.0]           → 2つの数値で表せる
3次元: 立体空間の位置       → [1.0, 2.0, 3.0]      → 3つの数値で表せる
768次元: 768個の軸がある空間 → [0.2, -0.5, ..., 0.3] → 768個の数値で表せる

人間は3次元までしか直感的に想像できないが、数学的には何次元でも同じ演算(距離計算、内積など)が成立する。次元が多いほど、より多くの「意味の側面」を表現できる

例えるなら:

  • 2次元で人を表す: [身長, 体重] → 大まかな体格しか分からない
  • 5次元で人を表す: [身長, 体重, 年齢, 視力, 握力] → もう少し詳しい
  • 768次元で文を表す: 768個の「意味の軸」で、ニュアンスや文脈まで捉える

「近い」= 「似ている」

Embeddingの最も重要な性質はこれだ:

意味が似ているデータは、ベクトル空間で近い位置に配置される

この「近さ」を数値で測る方法がコサイン類似度(Cosine Similarity)だ(セクション5で詳述)。

この記事で使う用語

用語 意味
ベクトル 数値の配列。[0.2, -0.5, 0.8] のようなもの
次元(dimension) ベクトルの要素数。768次元 = 768個のfloat
トークン(token) テキストの最小処理単位。単語やサブワード
Transformer 現代のEmbeddingモデルの基盤アーキテクチャ
Cosine Similarity 2つのベクトルの方向の近さを測る指標(-1〜+1)

2. ベクトル化・ベクトル検索・RAG — 3つの違い

この記事で最も重要な区別。この3つは混同されやすいが、まったく別のレイヤーの技術だ。

テキスト ──[ベクトル化]──> ベクトル ──[ベクトル検索]──> 類似文書 ──[RAG]──> LLM回答
           ^^^^^^^^^^^              ^^^^^^^^^^^^^^              ^^^^^
           変換する技術              探す技術                     活用する技術
           Embeddingモデル          ベクトルDB                   LLM + プロンプト

ベクトル化(Embedding)

テキストを数値のベクトルに変換する技術。

入力: "犬が公園で走っている"
出力: [0.20, -0.50, 0.80, ..., 0.30]  (768次元)

担当するのはEmbeddingモデル(OpenAI text-embedding-3, BGE, Cohere等)。

ベクトル検索(Vector Search)

ベクトルDB内から、クエリベクトルに近いベクトルを高速に見つける技術。

入力: [0.20, -0.50, 0.80, ..., 0.30]  (クエリベクトル)
出力: 類似度Top-K件の文書

担当するのはベクトルDB(Pinecone, Qdrant, pgvector等)。

RAG(Retrieval-Augmented Generation)

検索で取得した情報をLLMに渡して回答を生成するパターン

入力: ユーザーの質問 + 検索で取得した関連文書
出力: 外部知識に基づくLLMの回答

重要: RAGは「検索 + LLM」の組み合わせパターンの総称であり、検索手段はベクトル検索に限らない。キーワード検索でも、Grep検索でも、RAGは成立する。

なぜこの区別が重要か

Claude Codeが捨てたのはベクトル検索であって、RAG自体は捨てていない。Grep/Glob/Readで情報を検索し、LLMに渡して回答する——これもRAGの一形態だ。

従来のClaude Code:  テキスト → [ベクトル化] → [ベクトル検索] → [LLM生成]
現在のClaude Code:  テキスト → [Grep/Glob]  →                 [LLM生成]
                              ↑                                ↑
                         ベクトル化不要                     RAGは成立している

では、ベクトル検索を支えるEmbeddingとは、具体的にどういう仕組みなのか。


3. Embeddingの仕組み — テキストがベクトルになるまで

ここが本記事の技術的核心だ。テキストが768次元のベクトルになるプロセスを、ステップごとに分解する。

全体フロー

Step 1: トークン化(Tokenization)

テキストを処理可能な最小単位に分割する。現代のモデルはサブワード分割を使う。

入力: "機械学習は面白い"

単語分割の場合:  ["機械学習", "は", "面白い"]
サブワード分割: ["機械", "学習", "は", "面白", "い"]

代表的なトークナイザ:

  • BPE(Byte Pair Encoding): GPT系で使用。頻出するバイト列を結合
  • WordPiece: BERT系で使用。語彙に基づくサブワード分割
  • SentencePiece: 言語非依存。日本語でも前処理不要

Step 2: トークンID変換

各トークンを語彙テーブルのインデックス(整数)にマッピングする。

["[CLS]", "機械", "学習", "は", "面白", "い", "[SEP]"]
→ [101, 3245, 8901, 142, 5567, 234, 102]

[CLS][SEP]は特殊トークン。[CLS]は文全体の表現を集約する役割を持つ。

Step 3: Embedding層

各トークンIDをルックアップテーブルから密なベクトルに変換する。

トークンID 3245 ("機械") → [0.12, -0.34, 0.56, ..., 0.78]  (768次元)
トークンID 8901 ("学習") → [0.45, 0.23, -0.11, ..., 0.92]  (768次元)

この時点では、各トークンは文脈を考慮しない独立したベクトルだ。「銀行」が「お金の銀行」なのか「川の土手(bank)」なのかは、まだ区別できない。

さらに、トークンの順序情報を注入するために位置エンコーディングを加算する。

最終入力 = トークンEmbedding + 位置エンコーディング

Step 4: Transformer Encoder — ここが魔法の場所

TransformerのSelf-Attention機構が、各トークンに文脈情報を注入する。これがEmbeddingの品質を決定的に左右する。

Self-Attentionの仕組み

各トークンから3つのベクトルを生成する:

  • Query(Q): 「自分は何を探しているか」
  • Key(K): 「自分は何を持っているか」
  • Value(V): 「自分の情報」
Attention(Q, K, V) = softmax(Q · K^T / √d_k) · V

具体例で考えよう:

入力: "彼は銀行に預金した"

"銀行"のQueryが、他のすべてのトークンのKeyと照合される:
  "彼"   → 関連度: 低
  "は"   → 関連度: 低
  "に"   → 関連度: 低
  "預金" → 関連度: 高 ★
  "した" → 関連度: 低

→ "預金"との関連度が高いため、"銀行"のベクトルに
  「お金に関する銀行」の文脈情報が注入される

これが文脈依存表現だ。同じ「銀行」でも、「川の銀行」と「預金の銀行」で異なるベクトルが生成される。

Multi-Head Attention

実際には、複数のAttention「ヘッド」が並列に異なる関係性を学習する。

ヘッド1: 構文的関係(主語-述語)
ヘッド2: 意味的関係(銀行-預金)
ヘッド3: 位置的関係(近い単語同士)
...
ヘッド12: その他のパターン

BERTでは12ヘッド × 12層 = 144回のAttention計算が行われる。

層の階層性

浅い層(1-4層): 構文・文法を捉える
  └ 品詞、係り受け、語順パターン

中間層(5-8層): 意味関係を捉える
  └ 同義語、反義語、エンティティ関係

深い層(9-12層): 高次の抽象概念を捉える
  └ 感情、意図、トピック

Step 5: Pooling — トークン群を1つのベクトルに

Transformer Encoderの出力は、トークン数 × 768次元の行列だ。これを文全体を表す1つのベクトルに集約する必要がある。

Encoder出力:
  [CLS]  → [0.12, -0.34, ..., 0.78]
  機械    → [0.45, 0.23, ..., 0.92]
  学習    → [0.33, -0.11, ..., 0.56]
  は      → [0.01, 0.05, ..., 0.02]
  面白い  → [0.67, 0.44, ..., 0.81]
  [SEP]  → [0.08, -0.02, ..., 0.15]

主要なPooling手法:

手法 やり方 特徴
[CLS]トークン [CLS]の出力をそのまま使用 BERTのデフォルト。最新モデル(BGE等)で再び主流に
Mean Pooling 全トークンの平均を取る sentence-transformers系で広く使用。安定して高性能
Max Pooling 各次元の最大値を取る 特定の特徴が強調される

歴史的にはBERTの[CLS]→Sentence-BERTのMean Pooling→最新モデルで[CLS]回帰、と潮流が変化している。モデルのドキュメントで推奨Pooling方式を確認するのが確実だ。

# Mean Poolingの擬似コード
token_embeddings = transformer_output  # shape: (seq_len, 768)
attention_mask = ...  # パディングを除外

# マスク付き平均
sentence_embedding = (token_embeddings * attention_mask).sum(dim=0) / attention_mask.sum()
# shape: (768,)

4. 学習方法 — モデルはどう訓練されるか

Embeddingモデルの品質は、訓練方法で決まる。大きく分けて2段階ある。

事前学習: Masked Language Modeling (MLM)

BERTで導入された手法。テキストの一部を隠し、それを予測させる。

元の文: "私は東京に住んでいます"
マスク:  "私は[MASK]に住んでいます"
タスク:  [MASK] = "東京" を予測せよ

これにより、モデルは双方向の文脈理解を獲得する。教師データのラベル付けが不要なため、Wikipedia全文やWeb文書など大規模データで訓練できる。

Contrastive Learning(対照学習)— 現代Embeddingの鍵

MLMだけでは、文レベルの良質なEmbeddingは得られない。ここでContrastive Learningが登場する。

基本的な考え方

正例ペア(近づける):
  "犬が公園で走っている" ↔ "公園を駆け回る犬"

負例ペア(遠ざける):
  "犬が公園で走っている" ↔ "株式市場が急落した"

損失関数(InfoNCE Loss):

L = -log( exp(sim(anchor, positive) / τ) / Σ exp(sim(anchor, negative_i) / τ) )

τ: 温度パラメータ(一般的に0.02-0.2。MoCo: 0.07、SimCLR: 0.5)
sim: コサイン類似度

SimCSE: シンプルだが強力

面白いアプローチ: 同じ文を2回Transformerに通すだけ。Dropoutによってわずかに異なる表現が得られ、それを正例ペアとして使う。

"今日は天気がいい" → Dropout(0.1)を通す → ベクトルA
"今日は天気がいい" → Dropout(0.1)を通す → ベクトルB(わずかに異なる)

A と B を正例ペアとして訓練
→ 追加のデータ拡張なしで高品質なEmbeddingが得られる

教師ありContrastive Learning

NLI(自然言語推論)データセットを活用し、より高品質な訓練を行う。

含意(Entailment)= 正例:
  前提: "2人の男がカートを押している"
  仮説: "2人の男が荷物を移動している"

矛盾(Contradiction)= 強い負例:
  前提: "2人の男がカートを押している"
  仮説: "2人の男が座って休んでいる"

訓練データの規模感

モデル データ規模 パラメータ数
BERT (2018) 3.3B tokens 110M
E5 (2023) 270M text pairs 330M-7B
BGE-M3 (2024) 数億ペア 567M
OpenAI text-embedding-3 非公開(推定数十億ペア) 非公開

5. ベクトル空間と類似度

Cosine Similarity — なぜこれが標準か

2つのベクトルの類似度を測る最も一般的な指標。

cosine_similarity(A, B) = (A · B) / (||A|| × ||B||)

結果の範囲: -1 〜 +1
  +1: 完全に同じ方向(最も類似)
   0: 直交(無関係)
  -1: 正反対

なぜCosine Similarityが選ばれるか?

ベクトルの大きさ(magnitude)を無視し、方向だけを比較する。テキストの長さに左右されず、純粋に意味の類似性を測れる。

import numpy as np

def cosine_similarity(a, b):
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

# 実行例
sim_dog_cat = cosine_similarity(embed(""), embed(""))        # → 0.82
sim_dog_econ = cosine_similarity(embed(""), embed("経済学"))    # → 0.15

他の距離指標との使い分け

指標 数式 用途
Cosine Similarity A·B / (||A|| × ||B||) テキストEmbedding(標準)
Dot Product A · B 正規化済みベクトル(高速)
Euclidean Distance √Σ(a_i - b_i)² 画像、座標データ

正規化済みのベクトルでは、Cosine SimilarityとDot Productは等価になる。多くのEmbeddingモデルは正規化済みベクトルを出力するため、実質的にDot Productで十分。

ベクトル演算の直感

Word2Vec(2013年)で発見された有名な例:

vec("King") - vec("Man") + vec("Woman") ≈ vec("Queen")

ベクトル空間には意味の方向が存在する。King - Manで「男性性」を除去し、+ Womanで「女性性」を加える。結果として「女性の王」= Queenに近いベクトルが得られる。

これはベクトル空間が意味構造を持つことの直接的な証拠だ。ただし注意点がある。この線形的な演算はWord2Vecなどの静的Embeddingの性質であり、TransformerベースのEmbeddingでは各単語が文脈に応じて異なるベクトルを持つため、同じ演算が常に成立するわけではない。


6. ベクトル検索の実際 —

Embeddingで生成したベクトルを、実際に「検索」として使うために何が必要か。

ベクトル検索の全体像

ここで注目してほしいのは、事前準備が必要なことだ。文書をチャンクに分割し、全てをEmbedding化し、ベクトルDBに格納しておかなければならない。これが後述するClaude Codeの判断に効いてくる

チャンキング — 分割品質が検索品質を決める

長文をそのままEmbedding化すると、情報が希薄化する。適切なサイズに分割(チャンキング)が必要。

推奨設定:

チャンクサイズ: 200-500 トークン(汎用的な推奨値)
オーバーラップ: 10-20%(50-100トークン)

ただしクエリタイプによって最適値は異なる:

  • 事実確認クエリ(「〇〇の設立年は?」): 小さめ(256-512トークン)
  • 分析クエリ(「〇〇のメリデメを比較して」): 大きめ(1024+トークン)

手法比較:

手法 やり方 長所 短所
固定サイズ N文字/トークンで切る シンプル 文の途中で切れる
文単位 句点で分割、N文ずつ結合 意味の境界を保持 サイズ不均一
段落単位 改行2つで分割 論理的まとまり保持 段落サイズのばらつき
Recursive 階層的に分割を試行 柔軟、構造保持 実装が複雑
Semantic 意味の切れ目で分割 意味的まとまり最大化 計算コスト高
# LangChainのRecursiveCharacterTextSplitter(実務で最も使われる)
from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=50,
    separators=["\n\n", "\n", "", "", " ", ""]
)
chunks = splitter.split_text(document)

オーバーラップの効果:

チャンクサイズ: 500トークン、オーバーラップ: 75トークン(15%)

チャンク1: トークン[0:500]
チャンク2: トークン[425:925]    ← 75トークン重複
チャンク3: トークン[850:1350]   ← 75トークン重複

→ チャンク境界での情報損失を防ぐ

7. Agentic RAG — ベクトル検索を超えるアプローチ

ここからが本記事の核心だ。セクション3-6で解説したEmbedding+ベクトル検索は強力な技術だが、万能ではない。Claude Codeが下した判断を理解するために、Agentic RAGを深掘りする。

従来のRAG(ベクトル検索型)の弱点

セクション6で解説した従来のRAGには、構造的な弱点がある。

1. 事前準備コストが高い

文書追加・更新のたびに:
  テキスト抽出 → チャンク分割 → Embedding化 → DB格納 → インデックス更新

コードベースの場合:
  git commitのたびにインデックスを再構築する必要がある
  → 頻繁に変わるコードとの相性が悪い

2. 検索が1回きり

従来のRAG:
  質問 → ベクトル検索(1回) → Top-K取得 → LLM回答

  検索結果が的外れでも → そのまま回答してしまう
  情報が足りなくても → 再検索しない

3. チャンキングの罠

例: 関数の定義が500行ある場合
  → 200トークンのチャンクに分割される
  → 関数の冒頭と末尾が別チャンクになる
  → 「この関数の全体像」を1回の検索で取得できない

Agentic RAGとは

LLM自身が検索戦略を考え、実行し、評価し、必要なら再検索するアプローチ。

従来のRAG:
  質問 → 検索 → 回答          (パイプライン固定)

Agentic RAG:
  質問 → LLMが考える
       →「まずファイル構造を見よう」→ Glob実行
       →「この関数が怪しい」→ Read実行
       →「呼び出し元も確認したい」→ Grep実行
       →「十分な情報が集まった」→ 回答
                                  (LLMが動的に判断)

Claude Codeの実装

Claude Codeが使う検索ツールは3つだけ:

ツール 役割 従来のRAGで言えば
Glob ファイル名パターン検索 ベクトルDBのメタデータフィルタ
Grep ファイル内容のテキスト検索 キーワード検索(BM25)
Read ファイル内容の読み取り チャンクの取得

ベクトル化もベクトルDBも使わない。代わりに、LLMが「次にどのツールを使うか」「どんなクエリを投げるか」を自律的に判断する。

具体例: Claude Codeの検索フロー

ユーザー: 「認証機能のバグを直して」

Claude Codeの思考:
  1. 認証関連のファイルを探そう
     → Glob("**/auth*")  → src/auth/login.ts, src/auth/middleware.ts 等

  2. login.tsを読んでみよう
     → Read("src/auth/login.ts")  → コードを理解

  3. エラーハンドリングが怪しい。他にこの関数を呼んでいる箇所は?
     → Grep("authenticateUser")  → 3箇所見つかる

  4. テストファイルもチェック
     → Glob("**/auth*.test.*")  → テストの期待値を確認

  5. 原因を特定。修正案を提示。

このフローをベクトル検索で実現しようとすると:

  • コードベース全体を事前にEmbedding化する必要がある
  • git commitのたびにインデックス更新
  • 「authenticateUserの呼び出し元」のような構造的な検索はベクトル検索が苦手

なぜClaude Codeはベクトル検索を捨てたのか

観点 ベクトル検索 Agentic Search
事前準備 インデックス構築が必要 ゼロ
コード変更への追従 再インデックスが必要 常に最新を検索
検索の柔軟性 意味的類似度のみ パターン検索、構造検索、意味検索を動的に使い分け
精度(意味検索) 高い Grep/Globでは意味的類似は捉えられない
精度(構造検索) 低い 高い(呼び出し元、型定義など)
インフラ ベクトルDB必要 ファイルシステムのみ
セキュリティ ベクトルの保存に懸念 ローカルファイルのみ
コスト Embedding + DB運用 LLM呼び出し増

Claude Codeのケースでは、コードベースは頻繁に変更され、構造的な検索(呼び出し元、型定義、テストファイルの対応)が重要で、事前準備のコストが見合わなかった。


8. どちらを選ぶべきか

ベクトル検索が強い領域

  • 大量の静的文書を検索する場合(社内ドキュメント、FAQ、ナレッジベース)
  • 意味的な検索が重要な場合(「リモートワークのメリット」で「在宅勤務の利点」もヒットさせたい)
  • 多言語検索が必要な場合
  • データの更新頻度が低い場合
  • レコメンデーション、クラスタリング、異常検知など検索以外のベクトル活用もある場合

Agentic RAGが強い領域

  • 頻繁に変更されるデータを扱う場合(コードベース、日々更新されるログ)
  • 構造的な検索が重要な場合(ファイル名パターン、関数の呼び出し関係)
  • マルチステップの探索が必要な場合(1回の検索では答えが出ない複雑な質問)
  • 事前準備のコストをゼロにしたい場合
  • ツールの組み合わせが必要な場合(DB検索 + Web検索 + ファイル読み取り)

組み合わせという選択肢

二者択一ではない。Agentic RAGのツールの1つとしてベクトル検索を組み込むのが最も柔軟なアーキテクチャだ。

Agentic RAG
├── ツール1: ベクトル検索(意味的に近い文書を探す)
├── ツール2: Grep(キーワード完全一致検索)
├── ツール3: SQL(構造化データを問い合わせ)
├── ツール4: Web検索(最新情報を取得)
└── LLMが状況に応じて使い分ける

Claude Codeの場合、コードベースという特性上ベクトル検索のメリットが薄かっただけで、ドキュメント検索が主な用途なら、ベクトル検索はAgentic RAGの中でも依然として最強のツールだ。


9. まとめ

  1. ベクトル化とベクトル検索は別物。変換する技術(Embedding)と探す技術(Vector Search)を区別する
  2. Embeddingの核心はTransformerのSelf-Attention。文脈を理解したベクトルを生成する
  3. ベクトル検索は強力だがコストがある。事前準備、インデックス管理、チャンキング設計が必要
  4. Agentic RAGという選択肢がある。LLMが自律的に検索戦略を決め、複数ツールを使い分ける
  5. Claude Codeはベクトル検索を捨てた。コードベースという特性上、事前準備コストと構造検索の弱さが致命的だった
  6. どちらかではなく、組み合わせ。Agentic RAGのツールの1つとしてベクトル検索を使うのが最も柔軟

Embeddingは死んだのか?

まったく逆だ。 Claude Codeのケースはコードベースという特殊な領域での判断であり、Embeddingとベクトル検索は以下の場面で依然として最適解:

  • 大量の文書を意味的に検索するとき
  • 多言語対応が必要なとき
  • レコメンデーション・クラスタリング・異常検知
  • マルチモーダル検索(画像×テキスト)

技術を理解した上で、用途に応じて適切な道具を選ぶ。それがこの記事の結論だ。


参考文献

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?