"Jag sa att jag ville ha en B-film för fan!" Ett slut på ändlös rullning (och argument om vad man ska titta på...) Trött på att oändligt rulla igenom Netflix, osäker på vad du ska se härnäst? Tänk om du kunde bygga ditt eget anpassade, AI-drivna rekommendationssystem som förutsäger din nästa favoritfilm med precision? I den här handledningen guidar vi dig genom processen att skapa ett med hjälp av . Du lär dig hur moderna AI-rekommendationsmotorer fungerar och får praktisk erfarenhet av att bygga ditt eget system med . filmrekommendationssystem vektordatabaser (VectorDBs) Superlinked (Vill du hoppa direkt till koden? Kolla in vår repo på GitHub . Är du redo att prova rekommendatorsystem för ditt eget bruk? Skaffa en demo .) här här Låt oss rekommendera! Vi kommer att följa den här genom hela artikeln. Du kan också köra koden direkt från din webbläsare med hjälp av anteckningsboken Colab. Netflix rekommendationsalgoritm gör ett ganska bra jobb med att föreslå relevant innehåll - med tanke på den stora mängden alternativ (~16 000 filmer och TV-program 2023) och hur snabbt den måste föreslå program till användare. Hur gör Netflix det? Med ett ord, . semantisk sökning Semantisk sökning förstår innebörden och sammanhanget (både attribut och konsumtionsmönster) bakom användarfrågor och beskrivningar av filmer/TV-program, och kan därför ge bättre personalisering i sina frågor och rekommendationer än traditionella sökordsbaserade tillvägagångssätt. Men semantisk sökning innebär vissa - främst bland dem: 1) säkerställa korrekta sökresultat, 2) tolkningsbarhet och 3) skalbarhet - utmaningar som alla framgångsrika innehållsrekommendationer måste hantera. Genom att använda Superlinkeds bibliotek kan du dessa svårigheter. utmaningar övervinna I den här artikeln visar vi dig hur och baserat på dina preferenser. du använder Superlinked-biblioteket för att ställa in din egen semantiska sökning generera en lista över relevanta filmer Semantisk sökning - utmaningar Semantisk sökning förmedlar mycket värde i vektorsökning men innebär tre betydande utmaningar för inbäddning av vektorer för utvecklare: : För att säkerställa att dina inbäddningar korrekt fångar den semantiska innebörden av dina data krävs noggrant urval av inbäddningstekniker, träningsdata och hyperparametrar. Inbäddningar av dålig kvalitet kan leda till felaktiga sökresultat och irrelevanta rekommendationer. Kvalitet och relevans : Högdimensionella vektorrum är för komplicerade för att vara lätta att förstå. För att få insikter i relationerna och likheterna som kodas inom dem måste datavetare utveckla metoder för att visualisera och analysera dem. Tolkbarhet : Hantering och bearbetning av högdimensionella inbäddningar, särskilt i stora datamängder, kan anstränga beräkningsresurser och öka latensen. Effektiva metoder för indexering, hämtning och likhetsberäkning är avgörande för att säkerställa skalbarhet och realtidsprestanda i produktionsmiljöer. Skalbarhet Superlinked-biblioteket gör att du kan hantera dessa utmaningar. Nedan bygger vi en innehållsrekommendator (specifikt för filmer), börjar med information vi har om en given film, bäddar in denna information som en multimodal vektor, bygger ut ett sökbart vektorindex för alla våra filmer och använder sedan frågevikter för att justera våra resultat och komma fram till bra filmrekommendationer. Låt oss gå in i det. Skapa en snabb och pålitlig sökupplevelse med Superlinked Nedan utför du en semantisk sökning på Netflix-filmdataset med hjälp av följande element i Superlinked-biblioteket: Nyhetsutrymme - för att förstå färskheten (valuta och relevans) för dina data, identifiera nyare filmer. TextSimilarity space - för att tolka de olika bitarna av metadata du har om filmen, såsom beskrivning, titel och genre. Frågetidsvikter – låter dig välja vad som är viktigast i din data när du kör frågan, och optimerar därigenom utan att behöva bädda in hela datamängden igen, göra efterbearbetning eller använda en anpassad omrankningsmodell (dvs. minska latensen). Netflix-datauppsättningen och vad vi ska göra med den Att framgångsrikt rekommendera filmer är svårt, främst för att det finns så många alternativ (>9000 titlar 2023), och användare vill ha rekommendationer på begäran, omedelbart. Låt oss ta ett för att hitta något vi vill titta på. I vår av filmer känner vi till: datadrivet tillvägagångssätt datauppsättning beskrivning genre titel release_year Vi kan bädda in dessa ingångar och sätta ihop ett vektorindex ovanpå våra inbäddningar, vilket skapar ett utrymme som vi kan söka semantiskt. När vi har vårt indexerade vektorutrymme kommer vi: först, bläddra bland filmerna, filtrerade av en idé (hjärtlig romantisk komedi) justera sedan resultaten och ge mer vikt åt matchningar i vissa inmatningsfält (dvs viktning) sök sedan i beskrivning, genre och titel med olika söktermer för var och en och, efter att ha hittat en film som är en nära men inte exakt matchning, kan du också söka runt och använda den filmen som referens Installation och förberedelse av datamängder Ditt första steg är att installera biblioteket och importera de erforderliga klasserna. (Obs: Nedan ändrar du till om du kör detta i . Behåll "mimetype" om du kör i .) alt.renderers.enable(“mimetype”) alt.renderers.enable('colab') google colab github %pip install superlinked==5.3.0 from datetime import timedelta, datetime import altair as alt import os import pandas as pd from superlinked.evaluation.charts.recency_plotter import RecencyPlotter from superlinked.framework.common.dag.context import CONTEXT_COMMON, CONTEXT_COMMON_NOW from superlinked.framework.common.dag.period_time import PeriodTime from superlinked.framework.common.schema.schema import schema from superlinked.framework.common.schema.schema_object import String, Timestamp from superlinked.framework.common.schema.id_schema_object import IdField from superlinked.framework.common.parser.dataframe_parser import DataFrameParser from superlinked.framework.dsl.executor.in_memory.in_memory_executor import ( InMemoryExecutor, InMemoryApp, ) from superlinked.framework.dsl.index.index import Index from superlinked.framework.dsl.query.param import Param from superlinked.framework.dsl.query.query import Query from superlinked.framework.dsl.query.result import Result from superlinked.framework.dsl.source.in_memory_source import InMemorySource from superlinked.framework.dsl.space.text_similarity_space import TextSimilaritySpace from superlinked.framework.dsl.space.recency_space import RecencySpace alt.renderers.enable("mimetype") # NOTE: to render altair plots in colab, change 'mimetype' to 'colab' alt.data_transformers.disable_max_rows() pd.set_option("display.max_colwidth", 190) Vi behöver också förbereda datamängden - definiera tidskonstanter, ställa in URL-platsen för datan, skapa en datalagringsordbok, läsa in CSV:en i en pandas DataFrame, rensa dataramen och data så att den kan sökas ordentligt, och gör en snabb verifiering och översikt. (Se för detaljer.) cell 3 och 4 Nu när datasetet är förberett kan du optimera din hämtning med hjälp av Superlinked-biblioteket. Bygger ut indexet för vektorsökning Superlinkeds bibliotek innehåller en uppsättning kärnbyggstenar som vi använder för att konstruera ett index och hantera hämtning. Du kan läsa mer om dessa byggstenar . här Först måste du definiera ditt Schema för att berätta för systemet om dina data. # accommodate our inputs in a typed schema @schema class MovieSchema: description: String title: String release_timestamp: Timestamp genres: String id: IdField movie = MovieSchema() Därefter använder du Spaces för att säga hur du vill behandla varje del av data när du bäddar in. Vilka utrymmen som används beror på din datatyp. Varje utrymme är optimerat för att bädda in data för att ge högsta möjliga kvalitet på hämtningsresultaten. I rymddefinitioner beskriver vi hur indata ska vara inbäddade för att spegla de semantiska sambanden i vår data. # textual fields are embedded using a sentence-transformers model description_space = TextSimilaritySpace( text=movie.description, model="sentence-transformers/paraphrase-MiniLM-L3-v2" ) title_space = TextSimilaritySpace( text=movie.title, model="sentence-transformers/paraphrase-MiniLM-L3-v2" ) genre_space = TextSimilaritySpace( text=movie.genres, model="sentence-transformers/paraphrase-MiniLM-L3-v2" ) # release date are encoded using our recency space # periodtimes aim to reflect notable breaks in our scores recency_space = RecencySpace( timestamp=movie.release_timestamp, period_time_list=[ PeriodTime(timedelta(days=4 * YEAR_IN_DAYS)), PeriodTime(timedelta(days=10 * YEAR_IN_DAYS)), PeriodTime(timedelta(days=40 * YEAR_IN_DAYS)), ], negative_filter=-0.25, ) movie_index = Index(spaces=[description_space, title_space, genre_space, recency_space]) När du har ställt in dina utrymmen och skapat ditt index använder du käll- och exekveringsdelen av biblioteket för att ställa in dina frågor. Se . cellerna 10-13 i anteckningsboken Nu när frågorna är förberedda, låt oss gå vidare till att köra frågor och optimera hämtning genom att justera vikter. Förstå senaste nytt och hur man använder det i Superlinked Nyhetsutrymmet låter dig ändra resultaten av din fråga genom att i första hand dra in äldre eller nyare versioner från din datauppsättning. Vi använder 4, 10 och 40 år som våra periodtider så att vi kan ge år med fler titlar mer fokus - se ). cell 5 Lägg märke till pauserna i poängen vid 4, 10 och 40 år. Titlar äldre än 40 år får en -poäng. negative_filter Granska och optimera sökresultat med hjälp av olika frågetidsvikter Låt oss definiera en snabbfunktion för att presentera våra resultat i anteckningsboken. def present_result( result: Result, cols_to_keep: list[str] = ["description", "title", "genres", "release_year", "id"], ) -> pd.DataFrame: # parse result to dataframe df: pd.DataFrame = result.to_pandas() # transform timestamp back to release year df["release_year"] = [ datetime.fromtimestamp(timestamp).year for timestamp in df["release_timestamp"] ] return df[cols_to_keep] Enkla och avancerade frågor Superlinked-biblioteket låter dig utföra olika typer av frågor; här definierar vi två. Båda våra frågetyper av frågeställningar (enkla och avancerade) låter mig väga individuella utrymmen (beskrivning, titel, genre och naturligtvis nycitet) enligt mina preferenser. är att med en ställer jag in en frågetext och visar sedan liknande resultat i beskrivningen, titeln och genren. Skillnaden mellan dem enkel fråga Med en har jag mer finkornig kontroll. Om jag vill kan jag ange olika frågetexter i var och en av beskrivnings-, titel- och genreutrymmen. Här är frågekoden: avancerad fråga query_text_param = Param("query_text") simple_query = ( Query( movie_index, weights={ description_space: Param("description_weight"), title_space: Param("title_weight"), genre_space: Param("genre_weight"), recency_space: Param("recency_weight"), }, ) .find(movie) .similar(description_space.text, query_text_param) .similar(title_space.text, query_text_param) .similar(genre_space.text, query_text_param) .limit(Param("limit")) ) advanced_query = ( Query( movie_index, weights={ description_space: Param("description_weight"), title_space: Param("title_weight"), genre_space: Param("genre_weight"), recency_space: Param("recency_weight"), }, ) .find(movie) .similar(description_space.text, Param("description_query_text")) .similar(title_space.text, Param("title_query_text")) .similar(genre_space.text, Param("genre_query_text")) .limit(Param("limit")) ) Enkel fråga I enkla frågor ställer jag in min frågetext och lägger olika vikter beroende på deras betydelse för mig. result: Result = app.query( simple_query, query_text="Heartfelt romantic comedy", description_weight=1, title_weight=1, genre_weight=1, recency_weight=0, limit=TOP_N, ) present_result(result) Våra resultat innehåller några titlar som jag redan har sett. Jag kan hantera detta genom att vikta nycitet för att påverka mina resultat mot de senaste titlarna. Vikter är normaliserade till att ha en enhetssumma (dvs alla vikter justeras så att de alltid summeras till totalt 1), så du behöver inte oroa dig för hur du ställer in dem. result: Result = app.query( simple_query, query_text="Heartfelt romantic comedy", description_weight=1, title_weight=1, genre_weight=1, recency_weight=3, limit=TOP_N, ) present_result(result) Mina resultat (ovan) är nu alla efter 2021. Med den enkla frågan kan jag vikta vilket specifikt utrymme som helst (beskrivning, titel, genre eller senaste nytt) för att få det att räknas mer när jag returnerar resultat. Låt oss experimentera med detta. Nedan kommer vi att ge mer tyngd åt genren och nedviktstiteln - min frågetext är i princip bara en genre med lite extra sammanhang. Jag behåller min uppdatering som den är eftersom jag fortfarande vill att mina resultat ska vara partiska mot de senaste filmerna. result = app.query( simple_query, query_text="Heartfelt romantic comedy", description_weight=1, title_weight=0.1, genre_weight=2, recency_weight=1, limit=TOP_N, ) present_result(result) Den här frågan skjuter tillbaka releaseåret lite för att ge mig mer genreviktade resultat (nedan). Avancerad fråga Den avancerade frågan ger mig ännu mer finkornig kontroll. Jag behåller kontrollen över senaste tiden, men kan också ange söktext för beskrivning, titel och genre, och tilldela var och en en specifik vikt enligt mina preferenser, enligt nedan (och ), celler 19-21 result = app.query( advanced_query, description_query_text="Heartfelt lovely romantic comedy for a cold autumn evening.", title_query_text="love", genre_query_text="drama comedy romantic", description_weight=0.2, title_weight=3, genre_weight=1, recency_weight=5, limit=TOP_N, ) present_result(result) Sök med en specifik film Säg i mina senaste filmresultat, jag hittade en film som jag redan har sett och skulle vilja se något liknande. Låt oss anta att jag gillar White Christmas, en romantisk komedi från 1954 (id = tm16479) om sångare-dansare som samlas för en scenshow för att locka gäster till ett kämpande värdshus i Vermont. Genom att lägga till en extra -sats (med en parameter) till advanced_query, låter with_movie_query mig söka med den här filmen (eller vilken film jag gillar), och ger mig all den finkorniga kontrollen av separat undersökningsfrågetext och viktning. with_vector movie_id Först lägger vi till vår movie_id-parameter: with_movie_query = advanced_query.with_vector(movie, Param("movie_id")) Och sedan kan jag ställa in mina andra undersökningar till antingen tomma eller vad som är mest relevant, tillsammans med alla viktningar som är vettiga. Låt oss säga att min första fråga ger resultat som återspeglar scenframträdandet/bandaspekten av White Christmas (se ), men jag vill se en film som är mer familjeorienterad. Jag kan ange en description_query_text för att snedställa mina resultat i önskad riktning. cell 24 result = app.query( with_movie_query, description_query_text="family", title_query_text="", genre_query_text="", description_weight=1, title_weight=0, genre_weight=0, recency_weight=0, description_query_weight=1, movie_id="tm16479", limit=TOP_N, ) present_result(result) Men nu när jag ser mina resultat inser jag att jag faktiskt är mer på humör för något lättsamt och roligt. Låt oss justera min fråga därefter: Result = app.query( with_movie_query, description_query_text="", title_query_text="", genre_query_text="comedy", description_weight=1, title_weight=0, genre_weight=2, recency_weight=0, description_query_weight=1, movie_id="tm16479", limit=TOP_N, ) present_result(result) Okej, de här resultaten är bättre. Jag väljer en av dessa. Sätt på popcornen! Slutsats Superlinked gör det enkelt att testa, iterera och förbättra din hämtningskvalitet. Ovan har vi gått igenom hur du använder Superlinked-biblioteket för att göra en semantisk sökning på ett vektorutrymme, som Netflix gör, och returnera korrekta, relevanta filmresultat. Vi har också sett hur vi finjusterar våra resultat, justerar vikter och söktermer tills vi kommer till precis rätt resultat. Prova nu själv och se vad du kan uppnå! anteckningsboken Prova själv – Skaffa koden och demo! : Kolla in den fullständiga implementeringen i vår GitHub-repo . Dela den, finjustera den och gör den till din egen! 💾 Ta tag i koden här . : Vill du se detta fungera i en verklig installation? Boka en snabb och utforska hur kan förstärka dina rekommendationer. ! 🚀 Se det i aktion demo Superlinked Skaffa en demo nu Rekommendationsmotorer formar hur vi upptäcker innehåll. Oavsett om det är filmer, musik eller produkter – och nu har du verktygen för att bygga din egen. är vektorsökning framtiden Författare: Mór Kapronczay