TECH PLAY

アルゴリズム

イベント

マガジン

技術ブログ

本記事は 2025 年 9 月 22 日 に公開された「 A scalable, elastic database and search solution for 1B+ vectors built on LanceDB and Amazon S3 」を翻訳したものです。 この記事は Metagenomi の Owen Janson、Audra Devoto、Christopher Brown との共著です。 CRISPR によるゲノム編集から産業用バイオ触媒まで、酵素はヘルスケア、エネルギー、製造業における変革的な技術を支えています。しかし、ゲノム工学における Cas9 のように産業を変えるような新規酵素を発見するには、生命の系統樹にまたがる膨大な生物がコードする数十億種類の酵素を探索しなければなりません。DNA シーケンシングとメタゲノミクスの進歩により既知のタンパク質配列を格納した大規模な公開・独自データベースが構築されてきましたが、そこから価値の高い候補を見つけ出すのは生物学の問題であると同時にビッグデータの問題でもあります。 Metagenomi では、独自の大規模メタゲノミクスデータベース (MGXdb) を活用し、新規遺伝子編集システムのツールボックスを構築することで、根治的な治療法の開発に取り組んでいます。この記事では、Metagenomi が Amazon Web Services (AWS) のスケーラブルなインフラを使い、エンベディングに基づく高性能タンパク質データベースと検索ソリューションを構築して、数十億タンパク質規模の酵素発見に挑んでいる方法を紹介します。独自の大規模データベースに含まれるすべてのタンパク質をベクトル空間にエンベディングし、 Amazon Simple Storage Service (Amazon S3) 上に構築した LanceDB でデータにアクセスできるようにして、 AWS Lambda で検索することで、酵素発見を最近傍探索問題に変換し、これまで未探索だった発見空間に高速にアクセスできるようになりました。 ソリューション概要 このソリューションの中心にあるのが LanceDB です。LanceDB はオープンソースのベクトルデータベースで、インデックス付きベクトルに対する高速な近似最近傍 (ANN) 検索を実現します。LanceDB は完全にファイルベースで Amazon S3 ストレージとも互換性があるため、サーバーレス構成に適しています。その結果、エンベディング済みタンパク質配列のデータベースを Amazon Elastic Block Store (Amazon EBS) のような永続ディスクではなく、比較的低コストな Amazon S3 に保存できます。常時稼働するサーバーは不要で、データベースをオンデマンドで検索するのに必要なのは、LanceDB を使って S3 上のデータから直接最近傍を見つける Lambda 関数だけです。 Metagenomi の大規模タンパク質データベースを表す数十億のベクトルエンベディングを取り込み・検索するために、データベースを均等なサイズのパーツ (フォルダ) に分割して Amazon S3 に低コストで保存し、それらを並列にインデックス化して Lambda による map-reduce アプローチで検索する方法を考案しました。以下の図がこのアーキテクチャを示しています。 処理は 4 つのステップで構成されています。 データのベクトル化 データのバケット分割 データの取り込みとインデックス作成 データベースへのクエリ データのベクトル化 LanceDB の高速な ANN 検索機能を利用するには、データをベクトル形式にする必要があります。Metagenomi のメタゲノミクスデータベースには数十億のタンパク質が含まれており、それぞれがアミノ酸の文字列です。各タンパク質を生物学的に意味のある情報を捉えたベクトルに変換するため、タンパク質言語モデル (pLM) に通し、モデルの隠れ層をそのタンパク質のベクトル表現として取得します。タンパク質エンベディングの生成にはさまざまな pLM が使用でき、求める生物学的情報と計算要件に応じて選択します。今回は AMPLIFY_350M モデル を使用しました。データベース全体へのスケーリングに十分な速度を持つ Transformer エンコーダモデルです。モデルの最終隠れ層に対して mean-pool を実行し、各タンパク質について 960 次元のベクトルを生成します。生成されたベクトルと対応する一意のタンパク質 ID は HDF5 ファイルに保存します。 データのバケット分割 タンパク質ベクトルを検索可能なデータベースにするために、LanceDB でクエリの ANN を高速に見つけるためのインデックスを構築します。しかしインデックス作成には時間がかかり、複数ノードへの分散も困難です。インデックス作成を高速化するため、まずデータをほぼ均等なサイズのバケットに分割します。エンベディング HDF5 ファイルを best-fit bin packing アルゴリズムで合計約 2 億ベクトルのバケットに割り当てます。バケット分割に使う具体的なサイズ決定方法は、ベクトルの数、次元数、フォーマットによって異なります。各バケットは Amazon S3 上の単一の LanceDB データベースオブジェクトストア内に独立したテーブルとして取り込まれます。 データをバケット分割することで、個別ノードで並列にインデックス化できる小さなデータベースを複数作成でき、インデックス作成時間を大幅に短縮できます。また、既存データ全体を再インデックスする代わりに、新しいバケットとしてデータを追加でき増分追加も容易です。 バケット分割データの取り込みとインデックス作成 ベクトル化されたデータがバケットに割り当てられたら、LanceDB テーブルに変換してインデックスを作成し、高速な ANN クエリを可能にします。データを LanceDB テーブルに変換する具体的な方法は LanceDB のドキュメント を参照してください。約 2 億ベクトルの各バケットに対して、コサイン距離の IVF-PQ インデックスを持つ LanceDB テーブルを作成します。インデックス作成では、パーティション数は挿入行数の平方根、サブベクトル数はベクトル次元数を 16 で割った値を使用します。 クエリをスムーズにするため、各テーブルは作成元のバケットにちなんだ名前を付け、単一の S3 ディレクトリにアップロードします。ファイル構造から見ると、複数テーブルを持つ 1 つの LanceDB データベースとして認識されます。 以下のコードスニペットは、 id カラムと embedding カラムを含む HDF5 ファイルからベクトルを LanceDB データベースに取り込み、コサイン距離による高速 ANN 検索用にインデックスを作成する例です。実行に必要なのは python >= 3.9 と lancedb 、 pyarrow 、 h5py パッケージです。このスニペットは非同期 LanceDB API を使用する lancedb バージョン 0.21.1 でテスト・開発されています。 from typing import List, Iterable from itertools import islice from math import sqrt import pyarrow as pa import datetime import asyncio import lancedb import h5py def batched(iterable: Iterable, n: int) -> Iterable[List]: """Yield batches of n items from iterable.""" while batch := list(islice(iterable, n)): yield batch async def vectors_to_db( vectors: str, db: str, table_name: str, vector_dim: int, ingestion_batch_size: int, ) -> int: """Ingest and index vectors from an HDF5 file into a LanceDB table. Args: vectors (str): An HDF5 file containing protein IDs and their 960-dimension vector representations. db (str): Path to the LanceDB database. table_name (str): Name of the table to create. vector_dim (int): Dimension of the vectors. """ # create db and table custom_schema = pa.schema( [ pa.field("embedding", pa.list_(pa.float32(), vector_dim)), pa.field("id", pa.string()), ] ) # count the total number of rows as they are added to the table total_rows = 0 # open a connection to the new database and create a table with await lancedb.connect_async(db) as db_connection: with await db_connection.create_table( table_name, schema=custom_schema ) as table_connection: # open vectors file with h5py.File(vectors, "r") as vectors_handle: # create a generator over the rows rows = ( {"embedding": e, "id": i} for e, i in zip( vectors_handle["embedding"], vectors_handle["id"], ) ) # insert rows in batches to avoid memory issues for batch in batched(rows, ingestion_batch_size): total_rows += len(batch) await table_connection.add(batch) # optimize the table and remove old data await table_connection.optimize( cleanup_older_than=datetime.timedelta(days=0) ) # configure the index for the table index_config = lancedb.index.IvfPq( distance_type="cosine", num_partitions=int(sqrt(total_rows)), num_sub_vectors=int( vector_dim / 16 ), ) # index the table await table_connection.create_index( "embedding", config=index_config ) # ingest and index your data asyncio.run( vectors_to_db( vectors="./my_vectors.h5", db="./test_db", table_name="bucket1", vector_dim=960, ingestion_batch_size=50000 ) ) ベクトル化、取り込み、各バケットのインデックス作成は、複数の AWS Batch ジョブで並列実行することも、単一の Amazon Elastic Compute Cloud (Amazon EC2) インスタンスで実行することもできます。 データベースへのクエリ データがバケット分割され Amazon S3 上の LanceDB データベースに取り込まれたら、クエリの手段が必要です。LanceDB は LanceDB Python API を使って Amazon S3 から直接クエリできるため、Lambda 関数でユーザーが指定したクエリベクトルを受け取り、ANN を検索して結果を返すことができます。ただし、データが複数テーブルにバケット分割されているため、各バケットで最近傍を検索し、結果を集約してからユーザーに返す必要があります。 クエリワークフローは AWS Step Functions の ステートマシン として実装しています。各バケットに対するクエリ処理を Lambda プロセスとして管理し、最後に単一の Lambda プロセスがデータを集約して結果の ANN を .csv ファイルとして Amazon S3 に書き込みます。AWS Batch プロセスやローカル実行でも代替可能です。以下のスニペットは、1 つのバケットに対して ANN クエリを実行するプロセスの例です。実行に必要なのは python >= 3.9 と pandas 、 lancedb パッケージです。取り込みセクションと同様に、非同期 LanceDB API と lancedb バージョン 0.21.1 を使用しています。 from typing import List, Iterable import asyncio import lancedb import pandas import random async def run_query_async( lancedb_s3_uri: str, table_name: str, q_vec: List[float], k: int, vec_col: str, n_probes: int, refine_factor: int, ) -> pandas.DataFrame: """Run a query on a LanceDB table. Args: lancedb_s3_uri (str): S3 URI of the LanceDB database. table_name (str): Name of the table to query. q_vec (List[float]): Query vector. k (int): Number of nearest neighbors to return. vec_col (str): Column name of the vector column. n_probes (int): Number of probes to use for the query. refine_factor (int): Refine factor for the query. Returns: pandas.DataFrame: DataFrame containing the approximate nearest neighbors to the query vector. """ # open a connection to the database and table with await lancedb.connect_async( lancedb_s3_uri, storage_options={"timeout": "120s"} ) as db_connection: with await db_connection.open_table(table_name) as table_connection: # query the approximate nearest neighbors to the query vector df = ( await table_connection.query() .nearest_to(q_vec) .column(vec_col) .nprobes(n_probes) .refine_factor(refine_factor) .limit(k) .distance_type("cosine") .to_pandas() ) return df # query the example bucket we produced in the last section bucket1_df = asyncio.run( snippets.run_query_async( lancedb_s3_uri="s3://mg-analysis/owen/20250415_lancedb_snippet_testing/test_db/", table_name="bucket1", q_vec=[random.random() for _ in range(960)], k=3, vec_col="embedding", n_probes=1, refine_factor=1, ) ) 上記のクエリは以下の構造を持つ pandas DataFrame を返します。 embedding id _distance [-5.124435, 4.242000, …] id_1 0.000000 [-5.783999, 4.340500, …] id_2 0.001000 [-6.932943, 3.394850, …] id_3 0.04020 embedding カラムには最近傍のベクトル表現、 id カラムにはその ID、 _distance カラムにはクエリベクトルとのコサイン距離が格納されています。 各バケットが個別のノードで検索され、それぞれが最近傍の DataFrame を返した後、結果をマージしてユーザーに返す必要があります。以下のスニペットはその方法の例です。 def aggregate_nearest_neighbors( dfs: List[pandas.DataFrame], k: int ): """Aggregate the nearest neighbors for each query vector. Args: dfs (List[pandas.DataFrame]): A list of DataFrames containing the nearest neighbors queried from each bucket. k (int): The number of nearest neighbors to aggregate. Returns: pd.DataFrame: A DataFrame with the aggregated nearest neighbors. """ # concatenate the DataFrames and get the top k nearest neighbors return ( pandas.concat(dfs, ignore_index=True) .sort_values(by=["_distance"], ascending=True) .reset_index(drop=True) .head(k) ) # add the dataframes from querying each bucket to a list dfs = [bucket1_df, bucket2_df, bucket3_df, bucket4_df, bucket_5] # aggregate the nearest neighbors across all buckets nearest_neighbors_all_buckets_df = aggregate_nearest_neighbors(dfs, 5) 大量クエリの最適化 Lambda で S3 上の LanceDB データベースを直接検索する方法は、1 つまたは少数のクエリベクトルの ANN 検索には適していますが、数千から数百万のベクトルをクエリする必要があるユースケースもあります。 大量クエリに対してスケールする方法として、先述のクエリ実装を変更し、まずデータベースのバケットの 1 つをローカルストレージにダウンロードしてから LanceDB API でローカルに検索する方式を採用しています。データベースバケットのストレージサイズが大きいため、この実装は Lambda よりも AWS Batch ジョブに適しており、EBS ボリュームではなく最適化されたインスタンスストレージ (例: i4i インスタンス) の使用を推奨します。すべてのクエリ Batch ジョブが完了した後、最終ジョブが結果を集約してからユーザーに返します。並列クエリジョブと集約ジョブのオーケストレーションには Nextflow が使用できます。バケットをディスクにダウンロードするオーバーヘッドとレイテンシーは増加しますが、大量のクエリをより効率的に処理でき、常時稼働のサーバーベースデータベースも不要です。 ベンチマーク結果 インデックス戦略やデータベース分割サイズは、求めるパフォーマンスに依存します。ユースケースに合わせてカスタマイズする際の一般的な最適化ガイダンスを以下に示します。 Metagenomi が作成したデータベースの例では、AMPLIFY で生成した 960 次元のベクトルエンベディング 35 億件を格納しています。この 35 億ベクトルエンベディングを 2 億ベクトルごとに分割し、 i4i.8xlarge インスタンスで取り込みとインデックス作成を行ったところ、合計 108 コンピュート時間で完了しました。このソリューションはサーバーレスで S3 オブジェクトストアから直接クエリできるため、データベースの固定コストは Amazon S3 上のストレージ容量のみです (35 億ベクトルのインデックス済みデータベースで約 12.9 TB)。Lambda によるクエリは非常に低コストで、多くのクエリが 1 セント未満で実行できます。 一般的に、分割サイズが大きいほどクエリのコスト効率は高くなりますが、実行時間とインデックス作成時間は長くなります。単一分割で許容可能なクエリ応答時間を維持できる最大サイズまでスケールアップし、同時に Lambda 同時実行数の上限などの並列化の制約も考慮することを推奨します。Metagenomi では 2 億ベクトルごとの分割が、小規模・大規模両方のクエリでコストと実行時間の最適なバランスを示しました。取り込みとインデックス作成には i4i ファミリーなどのストレージ最適化インスタンスの使用を推奨します。ディスクベースのデータベースでクエリを実行する場合 (Lambda + Amazon S3 ではなく) も、ストレージ最適化インスタンスの使用を推奨します。Lambda 実装では、最大 50,000 ANN を要求する単一クエリ、または 5 ANN 未満で最大 100 シーケンスのマルチクエリを素早く処理できました。以下のグラフに示すように、実行時間は要求する ANN 数に対して線形に増加します。 まとめ この記事では、Metagenomi が LanceDB を Amazon S3 と AWS Lambda 上に実装し、数十億のタンパク質エンベディングを低コストで保存・検索する方法を紹介しました。この取り組みは、Metagenomi が根治的な遺伝子治療の開発に向けて推進する、新規酵素の発見とエンジニアリングプラットフォームの加速に貢献しています。クエリタンパク質の ANN エンベディング空間に数秒でアクセスできるようになったことで、大規模な解析パイプラインに高速検索手法を統合し、多様で新規な酵素ファミリーの発見を加速し、研究者がエンベディングをオンザフライで生成・検索する手段を提供してタンパク質エンジニアリングの取り組みを可能にしています。Metagenomi がタンパク質・DNA データベースの急速な拡大を続ける中、並列にインデックス化・検索できるデータベース分割による水平スケーリングが、将来のニーズに対応するエンベディングデータベースソリューションを実現しています。 この記事で紹介したソリューションはタンパク質 大規模言語モデル (LLM) で生成したベクトルに焦点を当てていますが、他のベクトル化されたデータセットにも適用できます。Amazon S3 と統合した LanceDB の詳細は LanceDB のドキュメント を参照してください。 参考文献 Fournier, Quentin, et al. “Protein language models: is scaling necessary?.” bioRxiv (2024): 2024-09. 著者について Audra Devoto Audra はメタゲノミクスのバックグラウンドを持つデータサイエンティストで、AWS 上の大規模ゲノミクスデータセットの取り扱いに長年の経験があります。Metagenomi では大規模解析プロジェクトを支えるインフラを構築し、MGXdb からの新規酵素発見を推進しています。 Christopher Brown Christopher Brown 博士は Metagenomi の Discovery チーム責任者です。メタゲノミクスの専門家であり、遺伝子編集応用に向けた多数の新規酵素システムの発見と特性解析を主導してきました。 Patrick O’Connor Patrick は AWS のシニア WorldWide AI プロトタイピングエンジニアで、クラウド上で生成 AI ソリューションとエンドツーエンドのプロトタイプを構築しています。大規模言語モデルと分散 AI システムの実装を専門としており、IoT、サーバーレス技術、ハイパフォーマンスコンピューティングの知見を活かして企業の複雑な課題解決に取り組んでいます。 Owen Janson Owen は Metagenomi のバイオインフォマティクスエンジニアで、大規模ゲノミクスデータセットの解析を支えるツールとクラウドインフラの構築に注力しています。 Pavel Novichkov Pavel Novichkov 博士は AWS のシニアソリューションアーキテクトで、ゲノミクスとライフサイエンスを専門としています。15 年以上のバイオインフォマティクスとクラウド開発の経験を持ち、ヘルスケア・ライフサイエンス分野のスタートアップが AWS 上でクラウドベースのソリューションを設計・実装する支援を行っています。NIH の National Center for Biotechnology Information でポスドク研究を行い、Berkeley Lab で 12 年以上計算研究科学者として勤務しました。 この記事は Kiro が翻訳を担当し、Solutions Architect の Sotaro Hikita がレビューしました。
レコメンドや最適化の仕事は、モデルの精度を上げることだと思われがちです。しかし、実サービスではそれだけで価値になるとは限りません。ユーザー体験を良くしたい。セッション数を伸ばしたい。広告収益も維持した...
はじめに こんにちは。レバレジーズ株式会社で研究員をしている永安です。普段は人材領域の推薦システムやLLMによる自動評価に関する研究開発に取り組んでいます。 2026年6月8日〜12日にGメッセ群馬で開催された、第40回人工知能学会全国大会(JSAI2026)に参加し、「人材領域における反実仮想機械学習を用いた相互推薦システムの説明手法」というテーマで発表してきました。 この記事では、JSAI2026全体の雰囲気と、私が個人的に面白いと感じた研究のトレンドを紹介します。事業会社の研究員の目線から見たJSAIの空気感が、これから参加を考えている方に少しでも伝われば嬉しいです。 ブースの様子 JSAI2026の全体の雰囲気 JSAI(人工知能学会全国大会)は、国内のAI研究者が一堂に会する最大級の学会です。今年は第40回・40周年の節目の大会で、Gメッセ群馬を会場に5日間のハイブリッド開催。前回のJSAI2025(大阪)が約5,000名規模だったこともあり、今年も国内最大級の盛り上がりでした。 参加して最初に感じたのは、企業のプレゼンスの大きさです。アカデミアの発表だけでなく、インダストリアルセッションでの企業発表や、展示ホールに並ぶ企業ブースが目を引きました。ブースでは各社のデータ活用やプロダクトの裏側が紹介されていて、休憩時間やレセプションでは企業関係者同士の交流もかなり活発でした。 個人的に大きかったのは、自分が研究している推薦(レコメンド)について、実際に業務で使っている方や、アカデミアで研究している方と密に話す機会を多く持てたことです。昨年参加したときは、チームが立ち上がったばかりで外に出せる成果がまだなく、話を聞いて回るのが中心でした。それが今年は、自分たちの取り組みとして話せるものを持って臨めたぶん、レコメンドを開発しているエンジニア、研究者と、一歩踏み込んだやり取りができたように思います。同じ推薦という土俵でも、事業側の制約や評価のリアルと、研究側の理論的な関心とでは見えている景色が違っていて、ブースや発表後の立ち話から得られる視点がとても多かったです。発表できるネタを持っていることが、こうした密度の高い会話の入り口になるのだと実感しました。 今年の大会全体を通して前面に出ていたのが、AIエージェントとPhysical AIです。LLMを核としたエージェント関連の発表・議論はあちこちで見られましたし、Physical AI(現実世界で身体を持って動くAI)も、スポンサー展示やチュートリアル講演を含めて大きな存在感を放っていました。 発表紹介:人材推薦の「希望の求人に行くには何を習得すると良いか?」に反実仮想で答える 人材領域の推薦は、「求職者→企業」と「企業→求職者」の双方向の好みを考える相互推薦(Reciprocal Recommendation)で、両者の嗜好の間には暗黙のトレードオフがあります。今回提案したのは、このトレードオフに説明性の観点から踏み込む反実仮想的な手法です。 コアは、「求職者自身は気に入っているのに、企業側のスコアが低くて推薦されない求人」に対して、求職者側のスコアを下げないという制約のもとで、企業側のスコアを押し上げるには何を変えればよいかを探索するという点にあります。これにより「あと何があれば、この求人に届いたのか」を提示でき、相互推薦のトレードオフを部分的に可視化できます。 このフレームワークで推薦結果を説明することにより、現時点でのユーザーに対する推薦だけでなく、ユーザーの将来のキャリアへのデータドリブンな助言をサービスに組み込むことが期待できます。 speakerdeck.com 気になった発表 大規模言語モデルエージェント間の社会的学習における文脈依存的パラメータ調整と相転移的振る舞い(堀部和也ほか/理化学研究所 環境が途中で変化する多腕バンディット課題をLLMエージェントの集団に適用し、各モデルの挙動に強化学習モデル(学習率・逆温度・社会的重み・同調指数など)を階層ベイズで当てはめた研究です。同質集団では、GPT-5.2は早期に探索をやめて多数派に同調し環境変化に固着する一方、Claude-Sonnet-4.5は探索を維持し、集団が大きいほど適応が良くなりました。さらに両者を混ぜると、GPT:Claudeが3:2→2:3になる一点で集団の適応可否がガラッと切り替わる、相転移のような閾値効果が現れます。Claudeが過半数になるとその探索が新しい社会的シグナルとなり、同調傾向の強いGPTが一斉に追従する、というモデルごとの傾向の違いが見られました。 感想 エージェントを使った調査ではLLMのコストが無視できず「どのモデルをどう分担させるか」が実務課題になりつつあります。その一般化された問いを綺麗な実験設定で示していた点が非常に良かったです。 Top-k方策分解に基づくランキング方策の効率的なオフ方策学習(R-POD)(岸本廉・田中滉一ほか/東京工業大学・慶應義塾大学) ログデータからランキング方策をオフ方策学習する問題で、従来は方策ベース(IPS)がランキング全体の重要度重みで分散が爆発し、回帰ベースは全ランキングの報酬推定が難しくバイアスが大きい、というジレンマがありました。R-PODは、ランキング方策を「上位k件を選ぶ第一段階方策」と「残りの下位を条件付きで選ぶ第二段階方策」に分解することでこれに対処します。第一段階は方策ベースの重要度重み付けを“ずっと小さいtop-kの行動空間”だけに適用して分散を大幅に抑え、第二段階はtop-kを条件とした残りの空間にのみ回帰を当ててバイアスを小さくする、という役割分担です。人工データ実験では、特にデータが少なく行動数が多い設定で、IPS-PGやDR-PGなどのベースラインを明確に上回りました。 感想 レコメンドではランキング全体を考慮することが重要で、上位と下位を分けてバイアスと分散を同時に抑えるという発想がとても綺麗でした。ランキングを考慮した最適化は自分の研究とも問題意識が重なり、特に学ぶところの多いポスターでした。 おまけ ホテル予約が遅れた 敗北者 研究員3人はAirbnbで民泊しましたが、焼肉パーティーで勝ちました。 研究員の作った漢料理 We are hiring! 最後までお読みいただきありがとうございました。会期を通して、推薦に関わる実務家・研究者の方々と密に交流でき、自分の研究を見つめ直すうえでも大きな刺激になりました。 レバレジーズでは、レバテックキャリアをはじめとする実サービスの現場課題を起点に、まだ方法論が固まっていない領域へ新しい手法を提案するような研究に取り組んでいます。実データ・実サービスと地続きでありながら、今回のように学会発表まで踏み込めるのは、事業会社の研究としては恵まれた環境だと感じています。 推薦システムや機械学習を専門に、「実データへのインパクト」と「研究としての新規性」の両方を追いたいという方は、ぜひ一度カジュアルにお話しできれば嬉しいです。 recruit.leverages.jp

動画

書籍