Yazılım mühendisleri bu dünyada heyecan verici bir yere sahiptir. Teknoloji yığını veya endüstri ne olursa olsun, işverenlerimizin amaç ve hedeflerine doğrudan katkıda bulunan sorunları çözmekle görevlendirildik. Bonus olarak, hedefimize gelen zorlukları hafifletmek için teknolojiyi kullanabiliyoruz.
Bu örnekte, Postgres için açık kaynaklı bir vektör benzerlik araması olan pgvector'un kurumsal verilerde mevcut olan veri benzerliklerini tanımlamak için nasıl kullanılabileceğine odaklanmak istedim.
Basit bir örnek olarak, pazarlama departmanının başlatmayı planladığı bir kampanya için yardıma ihtiyacı olduğunu varsayalım. Amaç, yazılım endüstrisiyle yakından bağlantılı sektörlerdeki tüm Salesforce hesaplarına ulaşmaktır.
Sonunda, en çok benzer olan ilk üç sektördeki hesaplara odaklanmak ve bu aracı gelecekte diğer sektörler için benzerlikler bulmak amacıyla kullanmak istiyorlar. Mümkünse, her zaman ilk üçe geri dönmek yerine, istenen sayıda eşleşen sektörü sağlama seçeneğini tercih ediyorlar.
Bu kullanım senaryosu benzerlik araması gerçekleştirmeye odaklanmaktadır. Bu alıştırmayı manuel olarak tamamlamak mümkün olsa da, birden fazla dil için önceden oluşturulmuş önceden eğitilmiş yerleştirmeler nedeniyle akla Wikipedia2Vec aracı geliyor. Kelime gömmeleri (vektörler olarak da bilinir), kelimelerin hem sözdizimsel hem de anlamsal bilgilerini içeren sayısal temsilleridir. Kelimeleri vektörler olarak temsil ederek, hangi kelimelerin anlamsal olarak diğerlerine “daha yakın” olduğunu matematiksel olarak belirleyebiliriz.
Örneğimizde, Salesforce'ta yapılandırılan her sektör için kelime vektörleri oluşturmak üzere basit bir Python programı da yazabilirdik.
pgvector
uzantısı bir Postgres veritabanı gerektirir. Ancak örneğimize ilişkin kurumsal veriler şu anda Salesforce'ta bulunmaktadır. Neyse ki Heroku Connect , Salesforce hesaplarını Heroku Postgres ile senkronize etmenin kolay bir yolunu sağlar ve bunu salesforce.account
adlı bir tabloda saklar. Ardından, Salesforce'taki her sektörü (VARCHAR anahtarı olarak) ve ilgili kelime vektörünü içeren salesforce.industries
adında başka bir tablomuz olacak.
Postgres'teki Salesforce verileri ve kelime vektörleri ile Java ve Spring Boot kullanarak bir RESTful API oluşturacağız. Bu hizmet gerekli sorgulamayı gerçekleştirecek ve sonuçları JSON formatında döndürecektir.
Çözümün üst düzey görünümünü şu şekilde gösterebiliriz:
Kaynak kodu GitLab'da bulunacaktır. git push heroku
komutunun verilmesi, Heroku'da bir dağıtımı tetikleyecek ve pazarlama ekibinin kolayca kullanabileceği bir RESTful API sunacaktır.
Üst düzey tasarım uygulandığında bir çözüm oluşturmaya başlayabiliriz. Salesforce oturum açma bilgilerimi kullanarak bu alıştırmanın verilerini görüntülemek için Hesaplar ekranına gidebildim. Kurumsal verilerin ilk sayfasına bir örnek:
Bu çaba için pazarlama ekibinin isteğini çözmek üzere Heroku'yu kullanmayı planladım. Heroku hesabımda oturum açtım ve similarity-search-sfdc
adlı yeni bir uygulama oluşturmak için Yeni Uygulama Oluştur düğmesini kullandım:
Uygulamayı oluşturduktan sonra Heroku Postgres eklentisini bulmak için Kaynaklar sekmesine gittim. Eklenti arama alanına “Postgres” yazdım.
Listeden Heroku Postgres'i seçtikten sonra Standart 0 planını seçtim, ancak pgvector, PostgreSQL 15 veya beta Essential katmanlı veritabanını çalıştıran Standart katmanlı (veya daha yüksek) veritabanı tekliflerinde mevcuttur .
Eklentiyi onayladığımda Heroku bir DATABASE_URL
bağlantı dizesi oluşturdu ve sağladı. Bunu uygulamamın Ayarlar sekmesindeki Yapılandırma Değişkenleri bölümünde buldum. Bu bilgiyi veritabanıma bağlanmak ve pgvector uzantısını şu şekilde etkinleştirmek için kullandım:
CREATE EXTENSION vector;
Daha sonra Heroku Connect eklentisini aradım ve buldum. Bunun bana Salesforce'taki kurumsal verilere bağlanmak için kolay bir yol sağlayacağını biliyordum.
Bu alıştırmada ücretsiz Demo Sürümü planı gayet iyi çalışıyor.
Bu noktada similarity-search-sfdc
uygulamasının Kaynaklar sekmesi şuna benziyordu:
Salesforce hesabımı Heroku Connect'e bağlamak için “ Heroku Connect'i Kurma ” talimatlarını takip ettim. Daha sonra senkronizasyon için Hesap nesnesini seçtim. Tamamlandığında, aynı Salesforce hesap verilerini Heroku Connect'te ve temel Postgres veritabanında görebildim.
SQL açısından bakıldığında yaptığım şey, aşağıdaki tasarıma sahip bir salesforce.account
tablosunun oluşturulmasıyla sonuçlandı:
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 );
Benzerlik aramasının beklendiği gibi çalışabilmesi için her Salesforce hesap sektörü için kelime vektörleri oluşturmam gerekiyordu:
Birincil kullanım durumu, yazılım endüstrisi için benzerlikler bulma ihtiyacını gösterdiğinden, o endüstri için de bir kelime vektörü oluşturmamız gerekir.
Bu alıştırmada işleri basit tutmak için, bu görevi Python 3.9 ve şuna benzeyen embed.py
adlı bir dosyayı kullanarak manuel olarak yürüttüm:
from wikipedia2vec import Wikipedia2Vec wiki2vec = Wikipedia2Vec.load('enwiki_20180420_100d.pkl') print(wiki2vec.get_word_vector('software').tolist())
Lütfen dikkat: get_word_vector()
yöntemi, sektörün küçük harfle temsil edilmesini bekler.
Python embed.py
çalıştırmak, software
kelimesi için aşağıdaki kelime vektörünü oluşturdu:
[-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]
Kelime vektörlerini depolamak için aşağıdaki SQL komutunu kullanarak Postgres veritabanına bir industries
tablosu eklememiz gerekiyordu:
create table salesforce.industries ( name varchar not null constraint industries_pk primary key, embeddings vector(100) not null );
Oluşturulan industries
tablosuyla, oluşturulan kelime vektörlerinin her birini ekleyeceğiz. Bunu aşağıdakine benzer SQL ifadeleriyle yaparız:
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] ');
Lütfen unutmayın; Yazılım Endüstrisini (yazılım) küçük harfle temsil eden bir kelime vektörü oluştururken, industries.name
sütununun büyük harfle yazılan endüstri adıyla (Yazılım) eşleşmesi gerekir.
Oluşturulan tüm kelime vektörleri industries
tablosuna eklendikten sonra odak noktamızı RESTful API'yi tanıtmaya değiştirebiliriz.
Bu, bir yazılım mühendisi olarak tutkumun vites yükselttiği noktaydı çünkü elimdeki zorluğu çözecek her şeye sahiptim.
Daha sonra Spring Boot 3.2.2 ve Java (temurin) 17'yi kullanarak IntelliJ IDEA'da similarity-search-sfdc
projesini aşağıdaki Maven bağımlılıklarıyla oluşturdum:
<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>
Hem Hesap nesnesi hem de Endüstri (yerleştirme) nesnesi için, daha önce oluşturulan Postgres veritabanı tablolarıyla aynı hizada olan basitleştirilmiş varlıklar oluşturdum.
@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; }
Postgres tablolarına kolay erişim sağlamak için JpaRepository arayüzünü kullanarak aşağıdaki uzantıları ekledim:
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()
yönteminin, bu kullanım senaryosunu çözmek için tüm ağır işlerin gerçekleştirileceği yer olduğuna dikkat edin. Yöntem aşağıdaki parametreleri kabul edecektir:
industry
: benzerlikleri bulmak için endüstrilimit
: hesaplar sorgulanırken aranacak sektör benzerliklerinin maksimum sayısı
Yukarıdaki sorgumuzda Öklid uzaklık operatörünü (<->) not edin. Bu, benzerlik aramasını gerçekleştirmek için uzantının yerleşik operatörüdür .
Orijinal "Yazılım" sektörü kullanım durumu ve en yakın üç sektöre ayarlanan limit ile yürütülen sorgu şu şekilde görünecektir:
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;
Oradan, JPA depolarıyla etkileşim kurmak için AccountsService
sınıfını oluşturdum:
@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"); } } }
Son olarak, AccountsController
sınıfının RESTful bir giriş noktası sağlamasını ve AccountsService
bağlanmasını sağladım:
@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); } } }
Spring Boot hizmeti hazır olduğunda projeye aşağıdaki Procfile
ekledim ve Heroku'nun hizmetimiz hakkında daha fazla bilgi sahibi olmasını sağladım:
web: java $JAVA_OPTS -Dserver.port=$PORT -jar target/*.jar
Güvende olmak için, hangi Java ve Maven sürümlerinin beklendiğini belirtmek için system.properties
dosyasını ekledim:
java.runtime.version=17 maven.version=3.9.5
Heroku CLI'yi kullanarak, Heroku platformuna similarity-search-sfdc
hizmeti için GitLab depoma bir uzaktan kumanda ekledim:
heroku git:remote -a similarity-search-sfdc
similarity-search-sfdc
hizmetinin buildpack türünü de aşağıdaki komutla ayarladım:
heroku buildpacks:set https://github.com/heroku/heroku-buildpack-java
Son olarak, aşağıdaki komutu kullanarak similarity-search-sfdc
hizmetini Heroku'ya dağıttım:
git push heroku
Şimdi similarity-search-sfdc
uygulamasının Kaynaklar sekmesi aşağıda gösterildiği gibi göründü:
RESTful API çalışırken, Yazılım sektörüne en yakın olan ilk üç Salesforce sektörünü (ve ilgili hesapları) bulmak için aşağıdaki cURL komutunu verdim:
curl --location 'https://HEROKU-APP-ROOT-URL/accounts/similarities?industry=Software&limit=3'
RESTful API, aşağıdaki veriyle birlikte 200 OK HTTP
yanıt durumunu döndürür:
[ { "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" } ]
Sonuç olarak Teknoloji , Medya ve Elektronik sektörleri bu örnekte Yazılım sektörüne en yakın sektörlerdir.
Artık pazarlama departmanının bir sonraki kampanyaları için iletişime geçebilecekleri hesapların bir listesi var.
Yıllar önce Team Fortress 2 çok oyunculu video oyununu oynayarak itiraf etmek istediğimden daha fazla zaman harcadım. İşte 2012'deki çok eğlenceli bir etkinlikten bir ekran görüntüsü:
Hayatımın bu yönüne aşina olanlar size varsayılan oyuncu sınıfı seçimimin asker olduğunu söyleyebilir. Bunun nedeni askerin sağlık, hareket, hız ve ateş gücü açısından en iyi dengeye sahip olmasıdır.
Yazılım mühendislerinin gerçek dünyanın “asker sınıfı” olduğunu düşünüyorum çünkü her duruma uyum sağlayabiliyoruz ve beklentileri verimli bir şekilde karşılayan çözümler sunmaya odaklanabiliyoruz.
Birkaç yıldır her BT uzmanına uygulanabileceğini düşündüğüm aşağıdaki misyon beyanına odaklandım:
“Zamanınızı fikri mülkiyetinizin değerini artıran özellikler/işlevsellik sunmaya odaklayın. Diğer her şey için çerçevelerden, ürünlerden ve hizmetlerden yararlanın.”
-J.Vester
Bu yazının örneğinde, kurumsal verileri Postgres veritabanıyla senkronize etmek için Heroku Connect'ten yararlanabildik. Pgvector uzantısını yükledikten sonra bu Salesforce hesaplarından her benzersiz sektör için kelime vektörleri oluşturduk. Son olarak, sektörü başka bir sektöre en yakın olan Salesforce hesaplarını bulma sürecini basitleştiren bir Spring Boot hizmetini kullanıma sunduk.
Bu kullanım durumunu mevcut açık kaynak teknolojileri, küçük bir Spring Boot hizmetinin eklenmesi ve Heroku PaaS ile misyon beyanıma tamamen bağlı kalarak hızlı bir şekilde çözdük. Bu çerçeveler, ürünler ve hizmetler olmadan ne kadar zamana ihtiyaç duyulacağını hayal bile edemiyorum.
Eğer ilgileniyorsanız, bu makalenin orijinal kaynak kodunu GitLab'da bulabilirsiniz:
https://gitlab.com/johnjvester/similarity-search-sfdc
Gerçekten harika bir gün geçirin!