ベクトル検索の使用法
ベクトル検索は、機械学習および人工知能を使用するシステムにとって基本となる概念です。ベクトル検索では、埋め込みモデルによって、テキストなどの非構造化データが、ベクトルと呼ばれる構造化データに変換されます。これにより、ユーザは、非構造化データ自体ではなく、それらのベクトルに対して演算を実行して、入力を処理し、応答を生成することができます。
InterSystems IRIS SQL では、ベクトルを圧縮された高性能の VECTOR 型で格納できるため、ベクトル化したデータを従来のリレーショナル・スキーマの一部として効率的に格納できます。
ベクトルと埋め込み
ベクトルは、埋め込みにおいて言語の意味論的意味を表すために使用できます。これらの埋め込みは、単語を高次元の幾何学的空間にマッピングする機械学習モデルである埋め込みモデルによって決定されます。最新の埋め込みベクトルは通常、数百から数千もの次元に及びます。同様の意味論的意味を持つ単語はその空間内の近い位置を占め、異なる意味論的意味を持つ語句は互いに離れた位置を占めます。こういった空間位置により、アプリケーションでは、埋め込みベクトルに対して演算を実行することによって、2 つの単語、さらには文の類似性をアルゴリズムで判定することが可能になります。
ベクトル検索では、ドット積など、2 つのベクトルの類似性を判定する演算を使用して、入力ベクトルとデータベースに格納されているベクトルとを比較します。検索が実行されるベクトルが埋め込みを表す場合、ベクトル検索によって、意味論的に入力に最も似ているテキストの部分をアルゴリズムで判定できます。このため、ベクトル検索は、情報の取得が含まれるタスクに最適です。
ベクトルの格納
多くのプラットフォームでリストなどのデータ構造を通じてベクトルがサポートされていますが、InterSystems IRIS® データ・プラットフォームでは、専用の VECTOR 型がサポートされています。この VECTOR 型では、チップレベルの最適化を利用して、複数の要素を一度に操作するものを含め、ベクトルに対して頻繁に実行される演算が効率的に実行されます。数値 VECTOR 型には、decimal (精度が最も高い)、double、および integer (精度が最も低い) の 3 つがあります。VECTOR は、標準の SQL データ型であるため、ベクトルを他のデータと共にリレーショナル・テーブルに格納して、SQL データベースを透過的にハイブリッドのベクトル・データベースに変換できます。
ベクトル・データは、INSERT 文を使用してテーブルに追加できます。また、%Library.Vector タイプのプロパティを使用し、ObjectScript を介してオブジェクトを作成して、そのプロパティにベクトルを格納することもできます。
多くの場合、InterSystems SQL のテーブルに保存されるベクトルは埋め込みを表し、手動で簡単に表したり、追加したりすることはできません。ほとんどのアプリケーションは大量の埋め込みベクトルを扱うため、これらの埋め込みをテーブルにロードするにはプログラムを使用することが重要です。以降のセクションでは、テキストを埋め込みに変換して、その埋め込みを VECTOR としてテーブルにロードする方法について説明します。
テキストの埋め込みへの変換
InterSystems IRIS で埋め込みをベクトルとして格納する前に、まずテキスト・ソースからそれらの埋め込みを作成する必要があります。一般には、4 つのステップでテキストを埋め込みに変換できます。
-
テキストを一連の埋め込みに変換するために使用するパッケージをインポートします。
-
選択した埋め込みモデルの入力仕様に合わせて、テキストを事前に処理します。
-
選択したパッケージのワークフローを使用して、モデルをインスタン化し、テキストを埋め込みに変換します。
-
個々の埋め込みを文字列に変換します。このステップは、後で埋め込みを VECTOR に変換するために必要です。
組み込み Python を使用すると、(任意のパッケージを使用して) テキストを埋め込みに変換する Python コードと共に、それらの埋め込みをデータベースに直接挿入できる ObjectScript コードを実行できます。Python パッケージを InterSystems IRIS にインポートする方法の詳細は、"Python パッケージのインストールおよびインポート" を参照してください。
例 : 組み込み Python を使用した埋め込みの作成
以下の例では、組み込みの Python リストとして渡された文の入力リストを取得して、それらを sentence_transformers パッケージを使用して埋め込みに変換し、後でテーブルに挿入できるよう埋め込みのリストを返します。埋め込みの挿入の詳細は、"VECTOR 型データの挿入" を参照してください。この例では、入力文は埋め込みモデルの仕様に合うように、事前に処理されていることが前提となっています。
ClassMethod GetEmbeddingPy(sentences) [ Language = python ]
{
import json
// import the package
import sentence_transformers
// create the model and form the embeddings
model = sentence_transformers.SentenceTransformer('all-MiniLM-L6-v2')
embeddings = model.encode(sentences)
// convert the embeddings to a string
embeddings_list = [str(embedding.tolist()) for embedding in embeddings]
return embeddings_list
}
VECTOR 型データの挿入
埋め込みを表す文字列のリストを用意したら、INSERT 文を使用することによって、またはオブジェクトを作成してそのオブジェクトのプロパティとして埋め込みを格納することによって、それらの埋め込みを VECTOR としてテーブルに挿入できます。以下の例は、INSERT を使用してデータを挿入する方法を示しています。
この例では、埋め込みは一意の識別子と共にテーブルに格納されます。これらの例では、埋め込みベクトルが挿入される際、ソース・テキストは同じ一意の識別子と共に別のテーブルに格納されていることが前提となっています。一意の識別子の値を共有することで、JOIN を実行して、埋め込みベクトルをそれが表すテキストにリンクすることが可能になります。埋め込みとテキストを同じテーブルに格納する場合、一意の識別子は不要です。
例
埋め込みごとに、埋め込みを目的のテーブルに追加する INSERT 文を実行します。TO_VECTOR を使用して、埋め込みの文字列表現を VECTOR に変換します。
以下のコマンドでは、1 つの埋め込みが Sample.Embeddings という名前のテーブルに挿入されます。このテーブルには、2 つの列が含まれており、1 つが埋め込み自体用で、もう 1 つが、埋め込みをその派生元のテキストにリンクするために使用できる一意の識別子用です (このテキストは、同じ識別子と共に別のテーブルに暗黙的に格納されます)。(この例では、埋め込みと一意の識別子のプレースホルダとして ? が使用されています。これらは通常、文のパラメータとしてプログラムで指定されるためです。)
INSERT INTO Sample.Embeddings (Embedding, UID)
VALUES (TO_VECTOR(?,double), ?)
以下のコード・サンプルでは、このクエリを使用して、1 つの埋め込みをテーブルに挿入します。
ClassMethod InsertEmbeddings(embedding As %String, uid As %Integer)
{
set sc=$$$OK
try {
set myquery = "INSERT INTO Sample.Embeddings (Embedding, UID)"
_"VALUES (TO_VECTOR(?,double), ?)"
set tStatement = ##class(%SQL.Statement).%New()
$$$ThrowOnError(##class(%SQL.Statement).%Prepare())
set rset = tStatement.%Execute(embedding, uid)
if (rset.%SQLCODE < 0) {
throw ##class(%Exception.SQL).CreateFromSQLCODE(rset.%SQLCODE,rset.%Message)
}
}
catch e {
set sc = e.AsStatus()
return sc
}
}
public void InsertEmbeddings(String embeddings, Integer uid) {
try {
// set connection parameters
IRISDataSource ds = new IRISDataSource();
ds.setServerName("127.0.0.1");
ds.setPortNumber(51776);
ds.setDatabaseName("USER");
ds.setUser("_SYSTEM");
ds.setPassword("SYS");
IRISConnection conn = ds.GetConnection();
String sql = "INSERT INTO Sample.Embeddings (Embedding, UID) " +
"VALUES (TO_VECTOR(?,double), ?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.SetString(embedding);
pstmt.SetInt(uid);
pstmt.executeUpdate();
pstmt.close();
} catch (Exception ex) {
System.out.println("caught exception: "
+ ex.GetClass().getName() + ": " + ex.GetMessage());
}
}
def insertEmbeddings(embeddings, uid):
// set the connection parameters
conn_string = "localhost:1972/USER"
username = "_system"
password = "SYS"
connection = iris.connect(conn_string, username, password)
cursor = connection.cursor()
try:
sql = "INSERT INTO Sample.Embeddings (Embedding, UID) " +
"VALUES (TO_VECTOR(?,double), ?)"
params = [embeddings,uid]
cursor.execute(sql,params))
cursor.close()
except Exception as ex:
print(ex)
finally:
if cursor:
cursor.close()
if connection:
connection.close()
static void InsertEmbeddings(string emb, Integer uid)
{
// set the connection parameters
String host = "127.0.0.1";
String port = "51776";
String username = "_SYSTEM";
String password = "SYS";
String namespace = "USER";
IRISConnection conn = new IRISConnection();
IRISConnect.ConnectionString = "Server = " + host
+ "; Port = " + port + "; Namespace = " + namespace
+ "; Password = " + password + "; User ID = " + username;
conn.Open();
String sql = "INSERT INTO Sample.Embeddings (Embedding, UID) " +
"VALUES (TO_VECTOR(?,double), ?)";
IRISCommand cmd = new IRISCommand(sql, conn);
cmd.ExecuteNonQuery();
cmd.Dispose();
conn.Close();
}
ベクトル検索の実行
ベクトル検索では、1 つのベクトルを使用して、データベース内に格納されている他の似たベクトルを検索できます。InterSystems SQL では、そのような検索を 1 つのクエリで実行できます。
現在、InterSystems SQL では、2 つのベクトルの類似性を判定する関数として、VECTOR_DOT_PRODUCT および VECTOR_COSINE の 2 つがサポートされています。これらの関数の値が大きいほど、ベクトルの類似性が高くなります。
例
以下の例は、SQL を使用して、VECTOR_DOT_PRODUCT を使用するクエリを発行し、意味論的に入力文に最も似ている記述を検索する方法を示しています。入力した検索語を埋め込みに変換した後、ORDER BY 節内で VECTOR_DOT_PRODUCT または VECTOR_COSINE を使用して、類似性の特に高いいくつかのテキストを返します。さらに、TOP 節を使用して、最も類似性の高い結果のみを選択します。
このクエリは、入力したクエリに基づいて、関連性が最も高い 5 つの記述を選択します。この例では、埋め込みと記述は別々のテーブル (それぞれ、Sample.Embeddings と Sample.Descriptions) に格納されており、固有の ID のフィールド (UID) でどの埋め込みがどの記述に対応しているかが識別されていることが前提となっています。このフィールドの JOIN によって、埋め込みと記述がリンクされます。埋め込みを、それが表すテキストと共に格納する場合、JOIN を実行する必要はありません。
以下の例は、入力されたユーザ・クエリに最も似ている 5 つの記述を選択する SQL 文を示しています (この例では、検索語の埋め込みのプレースホルダとして ? が使用されています。この値は通常、リテラルとしてではなく、パラメータとして指定されるためです)。
SELECT TOP 5 descrip.Description FROM Sample.Embeddings emb
JOIN Sample.Description descrip ON emb.UID = descrip.UID
ORDER BY VECTOR_DOT_PRODUCT(emb.Embeddings,
TO_VECTOR(?,double)) DESC
以下の例は、ダイナミック SQL でこのクエリを実行し、結果セットを反復処理して、複数の記述を 1 つの長い文字列に追加する ObjectScript メソッドを示しています。
ClassMethod GetSimilarDesc(searchTerms As %String)
{
set sc = $$$OK
try {
set query = "SELECT TOP 5 descrip.Description FROM Sample.Embeddings emb"
_"JOIN Sample.Description descrip ON emb.UID = descrip.UID"
_"ORDER BY VECTOR_DOT_PRODUCT(emb.Embeddings,"
_"TO_VECTOR(?,double)) DESC"
set tStatement = ##class(%SQL.Statement).%New()
$$$ThrowOnError(tStatement.%Prepare(query))
// convert input string to an embedding
set searchTermsEmbedding = ..GetEmbeddings(searchTerms)
set rset = tStatement.%Execute(searchTermsEmbedding)
if (rset.%SQLCODE < 0) {
throw ##class(%Exeception.SQL).CreateFromSQLCODE(rset.%SQLCODE,rset.%Message)
}
// process retrieved descriptions here and return the result
set retrievedInfo = ""
while rset.%Nest() {
set retrievedInfo = retrievedInfo_" Description: "_rset.%Get("Description")
}
return retrievedInfo
}
catch e {
set sc = e.AsStatus()
return sc
}
}