MilvusにAISAQを導入:10億スケールのベクトル検索がメモリ上で3,200倍安くなった
ベクターデータベースは、ミッションクリティカルなAIシステムの中核インフラとなり、そのデータ量は指数関数的に増大し、しばしば数十億ベクターに達します。このような規模になると、低レイテンシーの維持、精度の維持、信頼性の確保、レプリカやリージョン間での運用など、あらゆることが難しくなります。しかし、1つの課題が早い段階で表面化し、アーキテクチャの決定を支配する傾向があります。
高速検索を実現するために、ほとんどのベクターデータベースは、DRAM(ダイナミック・ランダム・アクセス・メモリー)に主要なインデックス構造を保持します。この設計は性能面では効果的ですが、拡張性には劣ります。DRAMの使用量はクエリ・トラフィックではなくデータ・サイズに比例し、圧縮や部分的なSSDオフロードを行ったとしても、インデックスの大部分はメモリ上に残らなければなりません。データセットが大きくなると、メモリコストはすぐに制限要因になります。
Milvusは既にDISKANNをサポートしており、これはディスクベースのANNアプローチで、インデックスの大部分をSSDに移行することでメモリへの負荷を軽減している。しかし、DISKANNは、検索中に使用される圧縮表現のために依然としてDRAMに依存している。Milvus 2.6は、DISKANNにインスパイアされたディスクベースのベクトルインデックスであるAISAQにより、これをさらに推し進める。KIOXIA社によって開発されたAiSAQのアーキテクチャは「ゼロDRAMフットプリント・アーキテクチャ」で設計されており、すべての検索クリティカルデータをディスク上に格納し、I/Oオペレーションを最小化するためにデータ配置を最適化する。これにより、10億ベクタのワークロードにおいて、実用的な性能を維持しながら、メモリ使用量を32GBから約10MBへと 3,200分の1に削減した。
以下のセクションでは、グラフベースのベクトル検索がどのように機能するか、メモリコストはどこから来るのか、そしてAISAQがどのように10億スケールのベクトル検索のコストカーブを再構築するかを説明します。
従来のグラフベースのベクトル検索の仕組み
ベクトル検索とは、高次元空間において、クエリに最も近い数値表現を持つデータ点を見つけるプロセスである。「最も近い」とは、単に余弦距離やL2距離などの距離関数に従った最小距離を意味する。小さなスケールでは、これは簡単です:クエリとすべてのベクトル間の距離を計算し、最も近いものを返します。しかし、10億スケールのような大規模になると、この方法はすぐに遅すぎて実用的ではなくなります。
網羅的な比較を避けるために、最新の近似最近傍探索(ANNS)システムはグラフベースのインデックスに依存している。すべてのベクトルに対してクエリを比較するのではなく、インデックスはベクトルをグラフに整理する。各ノードはベクトルを表し、エッジは数値的に近いベクトル同士を結ぶ。この構造により、システムは検索空間を劇的に狭めることができる。
グラフはあらかじめ、ベクトル間の関係のみに基づいて構築される。クエリには依存しない。クエリが到着すると、システムのタスクはグラフを効率的にナビゲートし、データセット全体をスキャンすることなく、クエリとの距離が最小のベクトルを特定することである。
探索はグラフ内のあらかじめ定義された開始点から始まる。この開始点はクエリから遠いかもしれないが、アルゴリズムはクエリに近いと思われるベクトルに向かって移動することで、その位置を段階的に改善する。このプロセスの間、検索は、候補リストと 結果リストという2つの内部データ構造を維持する。
そして、この過程で最も重要な2つのステップは、候補リストの拡張と結果リストの更新である。
候補リストの拡張
候補リストは、検索が次に進む可能性のある場所を表す。これは、クエリとの距離に基づいて有望と思われるグラフ・ノードの優先順位付けされた集合である。
各反復で、アルゴリズムは
これまでに発見された最も近い候補を選択する。候補リストから、クエリとの距離が最小のベクトルを選択する。
そのベクトルの近傍をグラフから取得する。これらの近傍ベクトルは、インデックス構築時に現在のベクトルに近いと特定されたベクトルである。
未訪問の近傍を評価し、候補リストに追加する。まだ探索されていない各近傍について、アルゴリズムはクエリとの距離を計算する。以前に訪問した近傍はスキップされ、新しい近傍が有望であれば候補リストに挿入される。
候補リストを繰り返し拡張することで、探索はグラフのますます関連性の高い領域を探索する。これによってアルゴリズムは、全ベクトルのごく一部を調べるだけで、より良い答えに向かって着実に進むことができる。
結果リストの更新
同時に、アルゴリズムは結果リストを保持し、最終出力に対してこれまでに見つかった最良の候補を記録する。探索が進むにつれて
探索中に遭遇した最も近いベクトルを追跡します。これには、拡張のために選択されたベクトルや、途中で評価された他のベクトルが含まれる。
クエリとの距離を保存します。これにより、候補をランク付けし、現在の上位K個の最近傍を維持することができます。
時間が経つにつれて、より多くの候補が評価され、より少ない改善が見つかると、結果リストは安定する。さらにグラフを探索しても近いベクトルが見つかりそうになくなると、探索は終了し、結果リストを最終的な答えとして返す。
簡単に言えば、候補リストは探索を制御し、結果リストはこれまでに発見された最良の答えをキャプチャする。
グラフベースのベクトル探索におけるトレードオフ
このグラフベースのアプローチが、そもそも大規模なベクトル検索を実用的なものにしている。すべてのベクトルをスキャンする代わりにグラフをナビゲートすることで、システムはデータセットのごく一部にしか触れずに高品質の結果を見つけることができる。
しかし、この効率はタダではない。グラフベースの検索は、精度とコストの間の基本的なトレードオフを露呈する。
より多くの近傍を探索することで、グラフの大部分をカバーし、真の最近傍を見逃す可能性を減らすことで精度が向上する。
同時に、探索範囲を広げるごとに、距離計算、グラフ構造へのアクセス、ベクトルデータの読み込みといった作業が増える。探索がより深く、より広くなるにつれて、これらのコストは蓄積されていく。インデックスがどのように設計されているかによって、これらのコストはCPU使用率の増加、メモリへの負荷の増加、ディスクI/Oの増加として現れます。
これらの相反する力のバランスをとることが、高いリコールと効率的なリソースの使用、グラフベースの検索設計の中心である。
DISKANNと AISAQはどちらもこの同じ緊張のもとに構築されていますが、これらのコストをどこでどのように支払うかについて、異なるアーキテクチャの選択をしています。
DISKANNがディスクベースのベクトル検索を最適化する方法
DISKANNは、これまでで最も影響力のあるディスクベースのANNソリューションであり、10億スケールのベクトル探索の世界的ベンチマークであるNeurIPS Big ANNコンペティションの公式ベースラインとして使用されています。その重要性は、性能だけでなく、グラフベースのANN検索が高速であるために完全にメモリ上に存在する必要はないということを証明したことにあります。
DISKANN は、SSD ベースのストレージと慎重に選択されたインメモリ構造を組み合わせることで、大規模なベクトル検索が、大規模な DRAM フットプリントを必要とすることなく、コモディティハードウェア上で強力な精度と低レイテンシを達成できることを実証しました。DISKANNは、検索のどの部分が高速でなければならず、どの部分が遅いアクセスでも許容できるかを再考することによって、これを実現した。
高いレベルでは、DISKANNは最も頻繁にアクセスされるデータをメモリに保持し、より大きく、より頻繁にアクセスされない構造をディスクに移動します。このバランスは、いくつかの重要な設計上の選択によって実現されている。
1.PQ距離を使って候補リストを拡張する
候補リストの拡張は、グラフベース検索で最も頻繁に行われる操作である。各拡張では、クエリーベクターと候補ノードの近傍との距離を推定する必要がある。完全な高次元ベクトルを用いてこれらの計算を行うには、ディスクからのランダムリードを頻繁に行う必要があり、計算上もI/O上も高価な操作となります。
DISKANNは、ベクトルを積量子化(PQ)コードに圧縮してメモリに保持することで、このコストを回避しています。PQコードは完全なベクトルよりもはるかに小さいが、それでもおおよその距離を推定するのに十分な情報を保持している。
候補の展開中、DISKANNはSSDから完全なベクトルを読み込む代わりに、これらのメモリ内のPQコードを使用して距離を計算します。これにより、グラフ探索中のディスクI/Oを劇的に削減し、SSDトラフィックの大部分をクリティカルパスから除外しながら、迅速かつ効率的に候補を探索することができます。
2.ディスク上のフルベクターとネイバーリストの協調配置
すべてのデータを圧縮したり、近似的にアクセスできるわけではありません。有望な候補が特定された後も、正確な結果を得るためには2種類のデータにアクセスする必要がある:
グラフ探索を続けるための隣接リスト
最終的な再ランク付けのための完全な(圧縮されていない)ベクトル
これらの構造体はPQコードよりもアクセス頻度が低いため、DISKANNはSSDに格納します。ディスクのオーバーヘッドを最小化するために、DISKANNは各ノードの隣接リストとその完全なベクトルをディスク上の同じ物理領域に配置します。これにより、1回のSSD読み取りで両方を確実に取得できます。
関連するデータを同位置に配置することで、DISKANNは検索時に必要なランダムディスクアクセスの回数を減らします。この最適化により、特に大規模において、拡張と再ランク付けの両方の効率が向上する。
3.並列ノード拡張によるSSDの有効利用
グラフベースのANN検索は反復プロセスである。各反復が1つの候補ノードのみを拡張する場合、システムは一度に1つのディスク読み取りを発行するだけで、SSDの並列帯域幅のほとんどが未使用のままになる。この非効率を避けるため、DISKANNは各反復で複数の候補を展開し、SSDに並列読み取り要求を送信します。このアプローチでは、利用可能な帯域幅をより有効に活用し、必要な反復回数の合計を減らすことができます。
beam_width_ratioパラメータは、いくつの候補を並列に展開するかを制御します:ビーム幅=CPUコア数×beam_width_ratio。比率を高くすると、探索の幅が広がり、精度が向上する可能性がありますが、計算量とディスクI/Oが増加します。
これを相殺するために、DISKANNはsearch_cache_budget_gb_ratio 、頻繁にアクセスされるデータをキャッシュするためにメモリを確保し、SSDの繰り返し読み込みを減らします。これらのメカニズムにより、DISKANNは精度、レイテンシ、I/O効率のバランスをとることができます。
なぜこれが重要なのか - そして限界はどこにあるのか
DISKANNの設計は、ディスクベースのベクトル検索にとって大きな前進です。PQコードをメモリ内に保持し、より大きな構造をSSDにプッシュすることで、完全にインメモリのグラフインデックスと比較して、メモリフットプリントを大幅に削減します。
同時に、このアーキテクチャは、検索に不可欠なデータを常時DRAMに依存している。PQコード、キャッシュ、制御構造は、トラバーサルの効率を維持するためにメモリに常駐していなければならない。データセットが何十億ベクトルにもなり、デプロイメントにレプリカやリージョンが追加されても、このメモリ要件が制限要因になる可能性がある。
AISAQはこのギャップを解決するために設計されています。
AISAQの仕組みと重要性
AISAQは、DISKANNのコアとなるアイデアに直接基づいていますが、PQデータをDRAMに保持する必要性をなくすという重要な転換点を導入しています。AISAQは、圧縮ベクトルを検索に不可欠な、常にメモリ内にある構造として扱う代わりに、それらをSSDに移動し、効率的なトラバーサルを維持するために、グラフデータをディスク上に配置する方法を再設計します。
これを実現するために、AISAQはノードのストレージを再編成し、グラフ検索に必要なデータ(フルベクトル、近傍リスト、PQ情報)を、アクセスの局所性に最適化されたパターンでディスク上に配置する。その目的は、より多くのデータをより経済的なディスクにプッシュするだけでなく、先に説明した検索プロセスを壊すことなくそうすることである。
さまざまなアプリケーション要件に対応するため、AISAQは2つのディスクベースストレージモードを提供している:パフォーマンスとスケールである。技術的な観点から見ると、これらのモードは主にPQ圧縮されたデータがどのように保存され、検索中にアクセスされるかが異なります。アプリケーションの観点からは、これらのモードは、オンライン意味検索や推薦システムに典型的な低レイテンシ要件と、RAGに典型的な超大規模要件の2つの異なるタイプの要件に対応している。
AISAQ-パフォーマンススピードの最適化
AISAQ-performanceは、データのコロケーションによりI/Oオーバーヘッドを低く抑えながら、すべてのデータをディスク上に保持します。
このモードでは
各ノードの完全なベクトル、エッジリスト、および隣接するノードのPQコードがディスクに一緒に保存されます。
候補の展開と評価に必要なデータはすべてコロケーションされているため、ノードを訪問してもSSDの読み込みは1回で済みます。
探索アルゴリズムから見ると、これはDISKANNのアクセスパターンを忠実に反映している。検索に不可欠なデータがすべてディスク上に存在するようになっても、候補の拡張は依然として効率的であり、実行時のパフォーマンスも同等です。
トレードオフはストレージのオーバーヘッドである。近傍のPQデータは複数のノードのディスクページに現れる可能性があるため、このレイアウトは冗長性をもたらし、全体のインデックスサイズを大幅に増加させる。
そのため、AISAQ-Performanceモードでは、ディスク効率よりもI/Oレイテンシの低さを優先している。アプリケーションの観点からは、AiSAQ-Performanceモードはオンライン意味検索に必要とされる10mSec台のレイテンシを提供することができる。
AISAQスケール:ストレージ効率の最適化
AISAQ-Scaleは逆のアプローチを取ります。すべてのデータをSSDに保存しながら、ディスクの使用量を最小限に抑えるように設計されています。
このモードでは
PQデータは、冗長性を排除して個別にディスクに保存されます。
これにより冗長性がなくなり、インデックス・サイズが劇的に小さくなる。
トレードオフとして、ノードとその近隣のPQコードにアクセスする場合、複数のSSD読み込みが必要となり、候補拡張時のI/O操作が増加する可能性がある。最適化されていないままだと、これは検索を大幅に遅らせることになる。
このオーバーヘッドを抑制するために、AISAQ-Scaleモードでは2つの追加最適化を導入しています:
PQデータの並べ替え。PQベクトルをアクセス優先度順に並べることで、局所性を向上させ、ランダムリードを減らす。
DRAM 内の PQ キャッシュ(
pq_read_page_cache_size)は、頻繁にアクセスされる PQ データを保存し、ホット・エントリに対するディスク読み出しの繰り返しを回避します。
これらの最適化により、AISAQ-Scaleモードは、実用的な検索性能を維持しながら、AISAQ-Performanceモードよりもはるかに優れたストレージ効率を達成している。この性能はDISKANNより低いままであるが、ストレージのオーバーヘッドはなく(インデックスサイズはDISKANNと同程度)、メモリフットプリントは劇的に小さくなっている。アプリケーションの観点からは、AiSAQは超ハイスケールでRAG要件を満たす手段を提供します。
AISAQの主な利点
すべての検索クリティカルデータをディスクに移動し、そのデータへのアクセス方法を再設計することで、AISAQはグラフベースのベクトル検索のコストとスケーラビリティプロファイルを根本的に変えます。その設計は3つの重要な利点をもたらします。
1.最大3,200倍のDRAM使用量削減
積量子化は、高次元ベクトルのサイズを大幅に縮小しますが、10億の規模になると、メモリ・フットプリントは依然として相当なものになります。圧縮後でさえ、従来の設計では検索中にPQコードをメモリに保持しなければならない。
例えば、10億個の128次元ベクトルを持つベンチマークであるSIFT1Bでは、構成にもよりますが、PQコードだけでおよそ30~120GBのDRAMを必要とします。完全な非圧縮ベクトルを保存するには、さらに480GBが必要になります。PQはメモリ使用量を4-16倍削減するが、それでも残りのフットプリントはインフラコストを支配するほど大きい。
AISAQはこの要件を完全に取り除きます。DRAMの代わりにSSDにPQコードを格納することで、永続的なインデックスデータによってメモリが消費されることがなくなる。DRAMは、候補リストや制御メタデータのような軽量で一時的な構造にのみ使用される。実際には、これによりメモリ使用量は数十ギガバイトから10MB程度に削減される。代表的な10億スケールの構成では、DRAMは32GBから10MBに減少し、3,200分の1になる。
SSDストレージの容量単価がDRAMの約30分の1であることを考えると、このシフトは総システム・コストに直接的かつ劇的な影響を与える。
2.追加のI/Oオーバーヘッドなし
PQコードをメモリからディスクに移動すると、通常、検索中のI/Oオペレーション数が増加する。AISAQは、データレイアウトとアクセスパターンを注意深く制御することで、これを回避している。AISAQでは、関連するデータをディスク上に散在させるのではなく、PQコード、フルベクター、近傍リストを同位置に配置し、一緒に検索できるようにしています。これにより、候補の拡張によってランダムリードが追加されることがない。
インデックスサイズとI/O効率のトレードオフを制御するために、AISAQはinline_pq パラメータを導入しています。このパラメータは、各ノードにインラインで格納されるPQデータの量を決定します:
低いinline_pq:インデックスサイズは小さくなるが、余分なI/Oが必要になる可能性がある。
inline_pqを高くする:インデックスサイズは大きくなるが、シングル・リード・アクセスは維持される。
inline_pq = max_degreeに設定すると、AISAQはノードの完全なベクトル、隣接リスト、およびすべてのPQコードを1回のディスク操作で読み込み、すべてのデータをSSDに保持しながらDISKANNのI/Oパターンに一致させます。
3.シーケンシャルPQアクセスによる計算効率の向上
DISKANNでは、候補ノードを拡張するには、R個の隣接ノードのPQコードを取得するためにR回のランダムなメモリアクセスが必要です。AISAQでは、1回のI/OですべてのPQコードを取得し、ディスクに順次格納することで、このランダム性を排除している。
シーケンシャル・レイアウトには2つの重要な利点がある:
シーケンシャルSSDリードは、散在するランダムリードよりもはるかに高速である。
連続したデータはキャッシュしやすく、CPUはPQ距離をより効率的に計算できる。
これにより、PQ距離計算の速度と予測可能性の両方が向上し、PQコードをDRAMではなくSSDに保存することによる性能コストを相殺することができます。
AISAQとDISKANNの比較:性能評価
AISAQがDISKANNとアーキテクチャ的にどのように異なるかを理解した後、次の質問は簡単です:これらの設計上の選択が実際のパフォーマンスとリソース使用にどのように影響するか?この評価では、AISAQとDISKANNを、検索性能、メモリ消費量、ディスク使用量という10億規模において最も重要な3つの次元で比較する。
特に、インラインPQデータ量(INLINE_PQ)の変化に対するAISAQの挙動を検証する。このパラメータはインデックスサイズ、ディスクI/O、実行効率のトレードオフを直接制御する。また、次元数は距離計算のコストとストレージ要件に強く影響するため、低次元と高次元のベクトル作業負荷で両アプローチを評価する。
セットアップ
全ての実験は、インデックスの挙動を分離し、ネットワークや分散システムの影響による干渉を避けるため、シングルノードシステム上で実施した。
ハードウェア構成
CPU:インテル® Xeon® Platinum 8375C CPU @ 2.90GHz
メモリースピード:3200MT/s、タイプ:DDR4DDR4、サイズ:32 GB
ディスク: 500 GB NVMe SSD
インデックス構築パラメータ
{
"max_degree": 48,
"search_list_size": 100,
"inline_pq": 0/12/24/48, // AiSAQ only
"pq_code_budget_gb_ratio": 0.125,
"search_cache_budget_gb_ratio": 0.0,
"build_dram_budget_gb": 32.0
}
クエリーパラメーター
{
"k": 100,
"search_list_size": 100,
"beamwidth": 8
}
ベンチマーク方法
DISKANNとAISAQの両方が、Milvusで使用されているオープンソースのベクトル検索エンジンであるKnowhereを使用してテストされました。この評価には2つのデータセットが使用された:
SIFT128D(1Mベクトル):画像記述子検索によく使われる128次元のベンチマーク。(生データセットサイズ≈488 MB)
Cohere768D (1Mベクトル):変換器ベースの意味探索に典型的な768次元の埋め込みセット。(生データセットサイズ≈2930 MB)
これらのデータセットは2つの異なる実世界のシナリオを反映している:コンパクトな視覚特徴量と大きな意味埋め込み。
結果
Sift128D1M (フルベクトル ~488MB)
Cohere768D1M (フルベクトル ~2930MB)
解析結果
SIFT128Dデータセット
SIFT128Dデータセットにおいて、AISAQは、すべてのPQデータがインライン化され、各ノードの必要なデータが1つの4KB SSDページ(INLINE_PQ = 48)に完全に収まる場合、DISKANNの性能に匹敵します。この構成では、検索に必要なすべての情報がコロケートされます:
フル・ベクター512B
ネイバーリスト:48 × 4 + 4 = 196B
近隣のPQコード: 48 × (512B × 0.125) ≒ 3072B
合計:3780B
ノード全体が1ページ内に収まるため、1回のアクセスに必要なI/Oは1回のみであり、AISAQは外部PQデータのランダムリードを避けることができる。
しかし、PQデータの一部だけがインライン化されている場合、残りのPQコードはディスク上の別の場所からフェッチしなければならない。このため、追加のランダムI/O操作が発生し、IOPS要求が急増し、大幅な性能低下につながります。
Cohere768D データセット
Cohere768Dデータセットでは、AISAQはDISKANNよりも性能が悪い。その理由は、768次元ベクトルが単純に1つの4KB SSDページに収まらないからです:
フルベクター:3072B
近傍リスト:48 × 4 + 4 = 196B
近傍のPQコード:48×(3072B×0.125)≒18432B
合計:21700B(≒6ページ)
この場合、すべてのPQコードがインライン化されていても、各ノードは複数ページにまたがる。I/O操作の数は一定ですが、各I/Oははるかに多くのデータを転送する必要があり、SSD帯域幅をはるかに高速に消費します。帯域幅が制限要因になると、AISAQはDISKANNに追いつけなくなります。特に、ノードごとのデータフットプリントが急速に増大する高次元のワークロードでは顕著です。
注意
AISAQのストレージレイアウトは通常、ディスク上のインデックスサイズを4倍から6倍増加させます。これは意図的なトレードオフであり、検索時に効率的なシングルページアクセスを可能にするため、フルベクター、近傍リスト、PQコードがディスク上に配置されています。これによりSSDの使用量は増加するが、ディスク容量はDRAMよりも大幅に安く、大容量のデータでも容易に拡張できる。
実際には、INLINE_PQ と PQ の圧縮率を調整することで、このトレードオフを調整することができる。これらのパラメータにより、固定されたメモリ制限に制約されることなく、ワークロードの要件に基づいて、検索パフォーマンス、ディスクフットプリント、およびシステム全体のコストのバランスをとることが可能になる。
結論
最新のハードウェアの経済性は変化している。DRAMの価格は依然として高いままですが、SSDの性能は急速に進歩しており、PCIe 5.0ドライブは現在、14 GB/秒を超える帯域幅を実現しています。その結果、検索に不可欠なデータを高価なDRAMからはるかに手頃なSSDストレージに移行するアーキテクチャは、ますます説得力を増しています。SSDの容量はDRAMのギガバイトあたり30倍以下であるため、これらの差はもはやわずかなものではなく、システム設計に重要な影響を与えます。
AISAQはこの変化を反映しています。大容量の常時オンメモリ割り当ての必要性を排除することで、ベクトル検索システムは、DRAMの制限ではなく、データサイズと作業負荷の要件に基づいて拡張することができます。このアプローチは、高速SSDが永続性だけでなく、アクティブな計算や検索においても中心的な役割を果たす「オールインストレージ」アーキテクチャに向けた幅広いトレンドと一致しています。パフォーマンスとスケールの2つの動作モードを提供することで、AiSAQは、セマンティック検索(最も低いレイテンシが必要)とRAG(非常に高いスケールが必要だが、レイテンシは中程度)の両方の要件を満たします。
このシフトはベクトル・データベースだけにとどまりそうもない。同様の設計パターンは、グラフ処理、時系列分析、そして従来のリレーショナル・システムの一部でさえもすでに出現しており、開発者は、許容可能なパフォーマンスを達成するためにデータをどこに置くべきかについての長年の思い込みを再考している。ハードウェアの経済性が進化し続けるにつれて、システム・アーキテクチャもそれに追随するようになるだろう。
ここで取り上げた設計の詳細については、ドキュメントをご覧ください:
Milvusの最新機能に関するご質問やディープダイブをご希望ですか?私たちの Discordチャンネルに参加するか、 GitHubに課題を提出してください。また、 Milvusオフィスアワーを通して、20分間の1対1のセッションを予約し、洞察やガイダンス、質問への回答を得ることもできます。
Milvus 2.6の機能についてもっと知る
Try Managed Milvus for Free
Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.
Get StartedLike the article? Spread the word



