paint-brush
pgvector を使用して企業データ内の類似点を特定する@johnjvester
805 測定値
805 測定値

pgvector を使用して企業データ内の類似点を特定する

John Vester14m2024/03/21
Read on Terminal Reader

長すぎる; 読むには

ワード ベクトルと類似性検索の力を利用して、企業データとのデータ相関関係を発見し、マーケティング キャンペーンを支援します。
featured image - pgvector を使用して企業データ内の類似点を特定する
John Vester HackerNoon profile picture
0-item
1-item


ソフトウェア エンジニアは、この世界で刺激的な地位を占めています。技術スタックや業界に関係なく、私たちは雇用主の目標や目的に直接貢献する問題を解決する使命を負っています。おまけに、テクノロジーを利用して、目の前に現れるあらゆる課題を軽減できるようになります。


この例では、Postgres 用のオープンソースのベクトル類似性検索であるpgvector を使用して、企業データ内に存在するデータの類似性を特定する方法に焦点を当てたいと思いました。

単純な使用例

簡単な例として、マーケティング部門が開始予定のキャンペーンについて支援を必要としていると仮定します。目標は、ソフトウェア業界と密接に連携する業界のすべてのSalesforceアカウントに連絡することです。


最終的には、最も類似した上位 3 つの業界のアカウントに焦点を当て、将来的にはこのツールを使用して他の業界の類似点を見つけられるようにしたいと考えています。可能であれば、常に上位 3 つを返すのではなく、希望する数の一致する業界を提供するオプションが欲しいと考えています。

高度な設計

この使用例は、類似性検索の実行を中心としています。この演習を手動で完了することも可能ですが、複数の言語用に事前にトレーニングされた埋め込みがすでに作成されているため、 Wikipedia2Vecツールが思い浮かびます。単語の埋め込み (ベクトルとも呼ばれます) は、構文情報と意味情報の両方を含む単語の数値表現です。単語をベクトルとして表すことにより、どの単語が他の単語に意味的に「近い」かを数学的に判断できます。


この例では、Salesforce で構成されている業界ごとにワード ベクトルを作成する簡単な Python プログラムを作成することもできます。


pgvector拡張機能には Postgres データベースが必要です。ただし、この例のエンタープライズ データは現在 Salesforce に存在します。幸いなことに、 Heraku Connect は、Salesforce アカウントを Heroku Postgres と同期し、 salesforce.accountというテーブルに保存する簡単な方法を提供します。次に、Salesforce 内の各業界 (VARCHAR キーとして) とそれに関連付けられた単語ベクトルを含むsalesforce.industriesという別のテーブルを作成します。


Postgres の Salesforce データとワード ベクトルを使用して、Java と Spring Boot を使用して RESTful API を作成します。このサービスは必要なクエリを実行し、結果を JSON 形式で返します。


ソリューションの概要を次のように説明します。


ソース コードは GitLab に存在します。 git push herokuコマンドを発行すると Heroku でのデプロイメントがトリガーされ、マーケティング チームが簡単に利用できる RESTful API が導入されます。

ソリューションの構築

高レベルの設計が完了したら、ソリューションの構築を開始できます。 Salesforce ログインを使用して、 「アカウント」画面に移動して、この演習のデータを表示することができました。エンタープライズ データの最初のページの例を次に示します。


Heroku アプリを作成する

今回の取り組みでは、マーケティングチームのリクエストを解決するために Heroku を使用することを計画しました。 Heroku アカウントにログインし、 [Create New App]ボタンを使用して、 similarity-search-sfdcという新しいアプリケーションを作成しました。


アプリを作成した後、 [リソース]タブに移動して Heroku Postgres アドオンを見つけました。アドオンの検索フィールドに「Postgres」と入力しました。


リストからHeroku Postgresを選択した後、 Standard 0プランを選択しましたが、 pgvector は、PostgreSQL 15 またはベータ版の Essential 層データベースを実行する Standard 層 (またはそれ以上) のデータベース製品で利用できます


アドオンを確認すると、Heraku はDATABASE_URL接続文字列を生成して提供しました。これは、アプリの [設定] タブの[構成変数]セクションで見つかりました。この情報を使用してデータベースに接続し、次のように pgvector 拡張機能を有効にしました。


 CREATE EXTENSION vector;


次に、 Heraku Connectアドオンを検索して見つけました。これにより、Salesforce のエンタープライズ データに簡単に接続できることがわかりました。


この演習では、無料のDemo Editionプランが問題なく機能します。


この時点で、 similarity-search-sfdcアプリの[リソース]タブは次のようになります。


Heroku Connect のセットアップ」の手順に従って、Salesforce アカウントを Heroku Connect にリンクしました。次に、同期するアカウントオブジェクトを選択しました。完了すると、同じ Salesforce アカウント データを Heroku Connect と基盤となる Postgres データベースで確認できるようになりました。


SQL の観点から見ると、私が行った結果、次の設計のsalesforce.accountテーブルが作成されました。


 create table salesforce.account ( createddate timestamp, isdeleted boolean, name varchar(255), systemmodstamp timestamp, accountnumber varchar(40), industry varchar(255), sfid varchar(18), id serial primary key, _hc_lastop varchar(32), _hc_err text );


ベクトルの生成

類似性検索が期待どおりに機能するためには、Salesforce アカウント業界ごとに単語ベクトルを生成する必要がありました。


  • 衣服
  • 銀行業
  • バイオテクノロジー
  • 工事
  • 教育
  • エレクトロニクス
  • エンジニアリング
  • エンターテインメント
  • 食料と飲料
  • ファイナンス
  • 政府
  • 健康管理
  • ホスピタリティ
  • 保険
  • メディア
  • 非営利
  • 他の
  • レクリエーション
  • 小売り
  • 配送
  • テクノロジー
  • 電気通信
  • 交通機関
  • 公共事業


主な使用例では、ソフトウェア業界の類似点を見つける必要があることが示されているため、その業界のワード ベクトルも生成する必要があります。


この演習では作業を簡単にするために、Python 3.9 とembed.pyというファイルを使用してこのタスクを手動で実行しました。これは次のようになります。


 from wikipedia2vec import Wikipedia2Vec wiki2vec = Wikipedia2Vec.load('enwiki_20180420_100d.pkl') print(wiki2vec.get_word_vector('software').tolist())


注意してください – get_word_vector()メソッドは業界を表す小文字を想定しています。


python embed.pyを実行すると、 softwareワードの次のワード ベクトルが生成されました。


 [-0.40402618050575256, 0.5711150765419006, -0.7885153293609619, -0.15960034728050232, -0.5692323446273804, 0.005377458408474922, -0.1315757781267166, -0.16840921342372894, 0.6626015305519104, -0.26056772470474243, 0.3681095242500305, -0.453583300113678, 0.004738557618111372, -0.4111144244670868, -0.1817493587732315, -0.9268549680709839, 0.07973367720842361, -0.17835664749145508, -0.2949991524219513, -0.5533796548843384, 0.04348105192184448, -0.028855713084340096, -0.13867013156414032, -0.6649054884910583, 0.03129105269908905, -0.24817068874835968, 0.05968991294503212, -0.24743635952472687, 0.20582349598407745, 0.6240783929824829, 0.3214546740055084, -0.14210252463817596, 0.3178422152996063, 0.7693028450012207, 0.2426985204219818, -0.6515568494796753, -0.2868216037750244, 0.3189859390258789, 0.5168254971504211, 0.11008890718221664, 0.3537853956222534, -0.713259220123291, -0.4132286608219147, -0.026366405189037323, 0.003034653142094612, -0.5275223851203918, -0.018167126923799515, 0.23878540098667145, -0.6077089905738831, 0.5368344187736511, -0.1210874393582344, 0.26415619254112244, -0.3066694438457489, 0.1471938043832779, 0.04954215884208679, 0.2045321762561798, 0.1391817331314087, 0.5286830067634583, 0.5764685273170471, 0.1882934868335724, -0.30167853832244873, -0.2122340053319931, -0.45651525259017944, -0.016777794808149338, 0.45624101161956787, -0.0438646525144577, -0.992512047290802, -0.3771328926086426, 0.04916151612997055, -0.5830298066139221, -0.01255014631897211, 0.21600870788097382, -0.18419665098190308, 0.1754663586616516, -0.1499166339635849, -0.1916201263666153, -0.22884036600589752, 0.17280352115631104, 0.25274306535720825, 0.3511175513267517, -0.20270302891731262, -0.6383468508720398, 0.43260180950164795, -0.21136239171028137, -0.05920517444610596, 0.7145522832870483, 0.7626600861549377, -0.5473887920379639, 0.4523043632507324, -0.1723199188709259, -0.10209759324789047, -0.5577948093414307, -0.10156919807195663, 0.31126976013183594, 0.3604489266872406, -0.13295558094978333, 0.2473849356174469, 0.278846800327301, -0.28618067502975464, 0.00527254119515419]


業界のテーブルの作成

単語ベクトルを保存するには、次の SQL コマンドを使用して、Postgres データベースにindustriesテーブルを追加する必要がありました。


 create table salesforce.industries ( name varchar not null constraint industries_pk primary key, embeddings vector(100) not null );


industriesテーブルを作成したら、生成された各単語ベクトルを挿入します。これは、次のような SQL ステートメントを使用して実行します。


 INSERT INTO salesforce.industries (name, embeddings) VALUES ('Software','[-0.40402618050575256, 0.5711150765419006, -0.7885153293609619, -0.15960034728050232, -0.5692323446273804, 0.005377458408474922, -0.1315757781267166, -0.16840921342372894, 0.6626015305519104, -0.26056772470474243, 0.3681095242500305, -0.453583300113678, 0.004738557618111372, -0.4111144244670868, -0.1817493587732315, -0.9268549680709839, 0.07973367720842361, -0.17835664749145508, -0.2949991524219513, -0.5533796548843384, 0.04348105192184448, -0.028855713084340096, -0.13867013156414032, -0.6649054884910583, 0.03129105269908905, -0.24817068874835968, 0.05968991294503212, -0.24743635952472687, 0.20582349598407745, 0.6240783929824829, 0.3214546740055084, -0.14210252463817596, 0.3178422152996063, 0.7693028450012207, 0.2426985204219818, -0.6515568494796753, -0.2868216037750244, 0.3189859390258789, 0.5168254971504211, 0.11008890718221664, 0.3537853956222534, -0.713259220123291, -0.4132286608219147, -0.026366405189037323, 0.003034653142094612, -0.5275223851203918, -0.018167126923799515, 0.23878540098667145, -0.6077089905738831, 0.5368344187736511, -0.1210874393582344, 0.26415619254112244, -0.3066694438457489, 0.1471938043832779, 0.04954215884208679, 0.2045321762561798, 0.1391817331314087, 0.5286830067634583, 0.5764685273170471, 0.1882934868335724, -0.30167853832244873, -0.2122340053319931, -0.45651525259017944, -0.016777794808149338, 0.45624101161956787, -0.0438646525144577, -0.992512047290802, -0.3771328926086426, 0.04916151612997055, -0.5830298066139221, -0.01255014631897211, 0.21600870788097382, -0.18419665098190308, 0.1754663586616516, -0.1499166339635849, -0.1916201263666153, -0.22884036600589752, 0.17280352115631104, 0.25274306535720825, 0.3511175513267517, -0.20270302891731262, -0.6383468508720398, 0.43260180950164795, -0.21136239171028137, -0.05920517444610596, 0.7145522832870483, 0.7626600861549377, -0.5473887920379639, 0.4523043632507324, -0.1723199188709259, -0.10209759324789047, -0.5577948093414307, -0.10156919807195663, 0.31126976013183594, 0.3604489266872406, -0.13295558094978333, 0.2473849356174469, 0.278846800327301, -0.28618067502975464, 0.00527254119515419] ');


注 – ソフトウェア業界 (ソフトウェア) を小文字で表現したワード ベクトルを作成しましたが、industry.name industries.nameは大文字の業界名 (ソフトウェア) と一致する必要があります。


生成されたすべてのワード ベクトルがindustriesテーブルに追加されたら、RESTful API の導入に焦点を移すことができます。

Spring Boot サービスの導入

目の前の課題を解決するためのすべてが整っていたため、ソフトウェア エンジニアとしての私の情熱が最高潮に達したのはこの時でした。


次に、Spring Boot 3.2.2 と Java (temurin) 17 を使用して、IntelliJ IDEA で次の Maven 依存関係similarity-search-sfdcプロジェクトを作成しました。


 <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.pgvector</groupId> <artifactId>pgvector</artifactId> <version>0.1.4</version> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>


AccountオブジェクトとIndustry (embedding) オブジェクトの両方に簡略化されたエンティティを作成し、前に作成した Postgres データベース テーブルと並べました。


 @AllArgsConstructor @NoArgsConstructor @Data @Entity @Table(name = "account", schema = "salesforce") public class Account { @Id @Column(name = "sfid") private String id; private String name; private String industry; } @AllArgsConstructor @NoArgsConstructor @Data @Entity @Table(name = "industries", schema = "salesforce") public class Industry { @Id private String name; }


JpaRepository インターフェイスを使用して、Postgres テーブルに簡単にアクセスできるように次の拡張機能を追加しました。


 public interface AccountsRepository extends JpaRepository<Account, String> { @Query(nativeQuery = true, value = "SELECT sfid, name, industry " + "FROM salesforce.account " + "WHERE industry IN (SELECT name " + " FROM salesforce.industries " + " WHERE name != :industry " + " ORDER BY embeddings <-> (SELECT embeddings FROM salesforce.industries WHERE name = :industry) " + " LIMIT :limit)" + "ORDER BY name") Set<Account> findSimilaritiesForIndustry(String industry, int limit); } public interface IndustriesRepository extends JpaRepository<Industry, String> { }


findSimilaritiesForIndustry()メソッドは、このユースケースを解決するためにすべての面倒な作業が行われることに注意してください。このメソッドは次のパラメータを受け入れます。


  • industry : 類似点を見つける業界
  • limit : アカウントのクエリ時に検索する業界の類似性の最大数


上記のクエリのユークリッド距離演算子 (<->) に注目してください。これは、類似性検索を実行するための拡張機能の組み込み演算子です。


元の「ソフトウェア」業界のユースケースと、最も近い 3 つの業界に制限が設定されている場合、実行されるクエリは次のようになります。


 SELECT sfid, name, industry FROM salesforce.account WHERE industry IN (SELECT name FROM salesforce.industries WHERE name != 'Software' ORDER BY embeddings <-> (SELECT embeddings FROM salesforce.industries WHERE name = 'Software') LIMIT 3) ORDER BY name;


そこから、JPA リポジトリと対話するためのAccountsServiceクラスを構築しました。


 @RequiredArgsConstructor @Service public class AccountsService { private final AccountsRepository accountsRepository; private final IndustriesRepository industriesRepository; public Set<Account> getAccountsBySimilarIndustry(String industry, int limit) throws Exception { List<Industry> industries = industriesRepository.findAll(); if (industries .stream() .map(Industry::getName) .anyMatch(industry::equals)) { return accountsRepository .findSimilaritiesForIndustry(industry, limit); } else { throw new Exception( "Could not locate '" + industry + "' industry"); } } }


最後に、 AccountsControllerクラスに RESTful エントリ ポイントを提供させ、 AccountsServiceに接続させました。


 @RequiredArgsConstructor @RestController @RequestMapping(value = "/accounts") public class AccountsController { private final AccountsService accountsService; @GetMapping(value = "/similarities") public ResponseEntity<Set<Account>> getAccountsBySimilarIndustry(@RequestParam String industry, @RequestParam int limit) { try { return new ResponseEntity<>( accountsService .getAccountsBySimilarIndustry(industry, limit), HttpStatus.OK); } catch (Exception e) { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } } }


Heroku にデプロイする

Spring Boot サービスの準備ができたら、次のProcfileプロジェクトに追加して、Heraku にサービスの詳細を知らせます。


 web: java $JAVA_OPTS -Dserver.port=$PORT -jar target/*.jar


安全のため、 system.propertiesファイルを追加して、期待される Java と Maven のバージョンを指定しました。


 java.runtime.version=17 maven.version=3.9.5


Heroku CLI を使用して、 similarity-search-sfdcサービスのリモートを GitLab リポジトリに追加して Heroku プラットフォームに追加しました。


 heroku git:remote -a similarity-search-sfdc


また、次のコマンドを使用して、 similarity-search-sfdcサービスのビルドパック タイプを設定します。


 heroku buildpacks:set https://github.com/heroku/heroku-buildpack-java


最後に、次のコマンドを使用して、 similarity-search-sfdcサービスを Heroku にデプロイしました。


 git push heroku


これで、 similarity-search-sfdcアプリの[リソース]タブが次のように表示されます。


類似性検索の実行

RESTful API を実行した状態で、次の cURL コマンドを発行して、ソフトウェア業界に最も近い上位 3 つの Salesforce 業界 (および関連するアカウント) を見つけました。


 curl --location 'https://HEROKU-APP-ROOT-URL/accounts/similarities?industry=Software&limit=3'


RESTful API は、次のペイロードとともに200 OK HTTP応答ステータスを返します。


 [ { "id": "001Kd00001bsP80IAE", "name": "CleanSlate Technology Group", "industry": "Technology" }, { "id": "001Kd00001bsPBFIA2", "name": "CMG Worldwide", "industry": "Media" }, { "id": "001Kd00001bsP8AIAU", "name": "Dev Spotlight", "industry": "Technology" }, { "id": "001Kd00001bsP8hIAE", "name": "Egghead", "industry": "Electronics" }, { "id": "001Kd00001bsP85IAE", "name": "Marqeta", "industry": "Technology" } ]


結果として、この例では、テクノロジー業界メディア業界、およびエレクトロニクス業界がソフトウェア業界に最も近い業界になります。


現在、マーケティング部門は、次のキャンペーンのために連絡できるアカウントのリストを持っています。

結論

何年も前、私は自分では認められないほど多くの時間を、 Team Fortress 2マルチプレイヤー ビデオ ゲームのプレイに費やしました。これは 2012 年に開催された、とても楽しかったイベントのスクリーンショットです。


私の人生のこの側面に詳しい人なら、私がデフォルトで選択したプレイヤー クラスは兵士だったことがわかるでしょう。これは、兵士が健康、動き、速度、火力のバランスが最も優れているためです。


ソフトウェア エンジニアは、どんな状況にも適応し、期待に応えるソリューションを効率的に提供することに注力できるため、現実世界の「兵士階級」であると感じています。


ここ数年、私は次のミッション ステートメントに焦点を当ててきました。これはあらゆる IT プロフェッショナルに適用できると考えています。


「知的財産の価値を高める機能を提供することに時間を集中してください。その他すべてにフレームワーク、製品、サービスを活用してください。」

- J. ヴェスター


この投稿の例では、Heraku Connect を利用してエンタープライズ データを Postgres データベースと同期することができました。 pgvector 拡張機能をインストールした後、これらの Salesforce アカウントから固有の業界ごとにワード ベクトルを作成しました。最後に、Spring Boot サービスを導入しました。これにより、別の業界に最も近い業界の Salesforce アカウントを見つけるプロセスが簡素化されました。


私たちは、既存のオープンソース テクノロジ、小さな Spring Boot サービス、および Heroku PaaS の追加を使用して、このユースケースを迅速に解決しました。これは私のミッション ステートメントに完全に準拠しています。これらのフレームワーク、製品、サービスがなければ、どれほどの時間がかかるか想像できません。


ご興味がございましたら、この記事の元のソース コードを GitLab で見つけることができます。


https://gitlab.com/johnjvester/similarity-search-sfdc


本当に素晴らしい一日をお過ごしください!