"Men B-Movie la'natini xohlayotganimni aytdim!"
Netflix-ni cheksiz aylantirishdan charchadingizmi, keyin nima tomosha qilishni bilmayapsizmi? Agar siz keyingi sevimli filmingizni aniq bashorat qiladigan o'zingizning shaxsiy, AI tomonidan boshqariladigan tavsiyalar tizimini yaratsangiz nima bo'ladi?
Ushbu qo'llanmada biz vektor ma'lumotlar bazalari (VectorDBs) yordamida filmlarni tavsiya qilish tizimini yaratish jarayoni bo'yicha sizga yo'l-yo'riq beramiz. Siz zamonaviy sun'iy intellektni tavsiya qiluvchi dvigatellar qanday ishlashini bilib olasiz va Superlinked yordamida o'z tizimingizni yaratish bo'yicha amaliy tajribaga ega bo'lasiz.
(Toʻgʻridan-toʻgʻri kodga oʻtmoqchimisiz? GitHub-dagi repo-ni shu yerda koʻring. Oʻzingiz uchun tavsiya qiluvchi tizimlarni sinab koʻrishga tayyormisiz? Bu yerda demo yuklab oling.)
Biz maqola davomida ushbu daftarni kuzatib boramiz. Shuningdek, kodni Colab yordamida brauzeringizdan to'g'ridan-to'g'ri ishga tushirishingiz mumkin.
Netflix-ning tavsiyalar algoritmi juda ko'p imkoniyatlarni (2023 yilda ~ 16 ming film va teledasturlar) va foydalanuvchilarga shoularni qanchalik tez taklif qilish kerakligini hisobga olsak, tegishli kontentni taklif qilishda juda yaxshi ish qiladi. Netflix buni qanday qiladi? Bir so'z bilan aytganda, semantik qidiruv .
Semantik qidiruv foydalanuvchi so'rovlari va filmlar/televidenie ko'rsatuvlari tavsiflari ortidagi ma'no va kontekstni (ham atributlar, ham iste'mol naqshlari) tushunadi va shuning uchun so'rovlar va tavsiyalarda an'anaviy kalit so'zlarga asoslangan yondashuvlarga qaraganda yaxshiroq shaxsiylashtirishni ta'minlaydi.
Ammo semantik qidiruv muayyan muammolarni keltirib chiqaradi, ular orasida eng muhimi: 1) aniq qidiruv natijalarini ta'minlash, 2) talqin qilish va 3) kengaytirilishi - har qanday muvaffaqiyatli kontentni tavsiya qilish strategiyasi hal qilishi kerak bo'lgan muammolar. Superlinked kutubxonasidan foydalanib, siz ushbu qiyinchiliklarni engishingiz mumkin.
Ushbu maqolada biz sizga Superlinked kutubxonasidan qanday foydalanishni ko'rsatamiz va o'zingizning semantik qidiruvingizni sozlashingiz va o'zingizning afzalliklaringiz asosida tegishli filmlar ro'yxatini yaratishingiz mumkin .
Semantik qidiruv vektor qidiruvida katta ahamiyatga ega, ammo ishlab chiquvchilar uchun vektorni joylashtirishda uchta muhim muammo tug'diradi:
Superlinked kutubxonasi ushbu muammolarni hal qilish imkonini beradi. Quyida biz maʼlum bir film haqidagi maʼlumotlardan boshlab, kontentni tavsiya qiluvchini (ayniqsa, filmlar uchun) yaratamiz, bu maʼlumotni multimodal vektor sifatida joylashtiramiz, barcha filmlarimiz uchun qidiriladigan vektor indeksini tuzamiz, soʻngra natijalarimizni oʻzgartirish va yaxshi film tavsiyalariga erishish uchun soʻrov ogʻirliklaridan foydalanamiz. Keling, bunga kirishamiz.
Quyida Superlinked kutubxonasining quyidagi elementlaridan foydalangan holda Netflix filmlari maʼlumotlar toʻplamida semantik qidiruvni amalga oshirasiz:
Muvaffaqiyatli filmlarni tavsiya qilish qiyin, chunki juda ko'p variantlar mavjud (2023 yilda > 9000 nom) va foydalanuvchilar darhol talab bo'yicha tavsiyalarni olishni xohlashadi. Keling, ko'rmoqchi bo'lgan narsani topish uchun ma'lumotlarga asoslangan yondashuvni qo'llaylik. Bizning filmlar to'plamida biz quyidagilarni bilamiz:
Biz ushbu ma'lumotlarni joylashtirishimiz va vektor indeksini o'rnatishlarimiz ustiga qo'yishimiz va semantik qidirishimiz mumkin bo'lgan bo'shliqni yaratishimiz mumkin.
Indekslangan vektor maydoniga ega bo'lgach, biz:
Sizning birinchi qadamingiz kutubxonani o'rnatish va kerakli sinflarni import qilishdir.
(Eslatma: Quyida, agar siz buni Google colab da ishga tushirayotgan bo'lsangiz, alt.renderers.enable(“mimetype”)
ni alt.renderers.enable('colab')
ga o'zgartiring. Agar siz github da bajarayotgan bo'lsangiz, “mimetype”ni saqlang.)
%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)
Shuningdek, biz ma'lumotlar to'plamini tayyorlashimiz kerak - vaqt konstantalarini aniqlang, ma'lumotlarning URL manzilini o'rnating, ma'lumotlar do'koni lug'atini yarating, CSV-ni pandas DataFrame-ga o'qing, ma'lumotlar ramkasi va ma'lumotlarni to'g'ri izlash uchun tozalang va tezkor tekshirish va umumiy ko'rinishni amalga oshiring. (Tafsilotlar uchun 3 va 4 katakchalarga qarang.)
Endi ma'lumotlar to'plami tayyor bo'lgach, Superlinked kutubxonasi yordamida qidirishni optimallashtirishingiz mumkin.
Superlinked kutubxonasida biz indeks yaratish va qidirishni boshqarish uchun foydalaniladigan asosiy qurilish bloklari to'plami mavjud. Ushbu qurilish bloklari haqida bu erda batafsilroq o'qishingiz mumkin.
Birinchidan, tizimga ma'lumotlaringiz haqida aytib berish uchun sxemangizni belgilashingiz kerak.
# accommodate our inputs in a typed schema @schema class MovieSchema: description: String title: String release_timestamp: Timestamp genres: String id: IdField movie = MovieSchema()
Keyinchalik, joylashda ma'lumotlarning har bir qismiga qanday munosabatda bo'lishni xohlayotganingizni aytish uchun bo'shliqlardan foydalanasiz. Qaysi bo'shliqlar ishlatilishi ma'lumotlar turiga bog'liq. Qidiruv natijalarining mumkin bo'lgan eng yuqori sifatini qaytarish uchun har bir bo'shliq ma'lumotlarni joylashtirish uchun optimallashtirilgan.
Kosmik ta'riflarda biz ma'lumotlarimizdagi semantik munosabatlarni aks ettirish uchun kirishlar qanday kiritilishi kerakligini tasvirlaymiz.
# 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])
Bo'shliqlarni o'rnatganingizdan va indeksingizni yaratganingizdan so'ng, so'rovlaringizni sozlash uchun kutubxonaning manba va ijrochi qismlaridan foydalanasiz. Daftardagi 10-13 kataklarga qarang.
So'rovlar tayyor bo'lgach, keling, so'rovlarni bajarish va og'irliklarni sozlash orqali qidirishni optimallashtirishga o'tamiz.
Yangilik maydoni ma'lumotlar to'plamidan eski yoki yangiroq nashrlarni afzal ko'rish orqali so'rov natijalarini o'zgartirish imkonini beradi. Biz 4, 10 va 40 yilni davr vaqtlari sifatida ishlatamiz, shunda biz ko'proq unvonlar bilan yillarga ko'proq e'tibor berishimiz mumkin - 5-hujayraga qarang).
4, 10 va 40 yoshda hisobdagi tanaffuslarga e'tibor bering. 40 yoshdan oshgan sarlavhalar negative_filter
ball oladi.
Natijalarimizni daftarda ko'rsatish uchun tezkor util funksiyasini aniqlaylik.
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]
Superlinked kutubxonasi har xil turdagi so'rovlarni bajarish imkonini beradi; bu erda ikkitasini aniqlaymiz. Bizning ikkala so'rov turlarimiz (oddiy va ilg'or) mening afzalliklarimga ko'ra alohida bo'shliqlarni (ta'rif, sarlavha, janr va, albatta, yangilik) tortishga imkon beradi. Ularning orasidagi farq shundaki, men oddiy so'rov bilan bitta so'rov matnini o'rnatdim va keyin tavsif, sarlavha va janr bo'shliqlarida shunga o'xshash natijalarni ko'rsataman.
Kengaytirilgan so'rov bilan menda yanada nozik nazorat bor. Agar xohlasam, tavsif, sarlavha va janr bo'shliqlarining har biriga turli xil so'rov matnlarini kiritishim mumkin. Mana so'rov kodi:
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")) )
Oddiy so'rovlarda men so'rov matnimni o'rnataman va ularning men uchun ahamiyatiga qarab turli og'irliklarni qo'llayman.
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)
Natijalarimiz men allaqachon ko'rgan ba'zi sarlavhalarni o'z ichiga oladi. Natijalarimni so'nggi unvonlarga moslashtirish uchun yangilikni tortish orqali men buni hal qila olaman. Og'irliklar birlik yig'indisiga ega bo'lish uchun normallashtiriladi (ya'ni, barcha og'irliklar har doim jami 1 ga teng bo'ladigan tarzda o'rnatiladi), shuning uchun ularni qanday o'rnatishingiz haqida tashvishlanishingiz shart emas.
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)
Mening natijalarim (yuqorida) hozir hammasi 2021 yildan keyin.
Oddiy so'rovdan foydalanib, natijalarni qaytarishda ko'proq hisobga olinishi uchun har qanday ma'lum bo'shliqni (tavsif, sarlavha, janr yoki yangilik) tortishim mumkin. Keling, bu bilan tajriba qilaylik. Quyida biz janr va unvonga ko'proq ahamiyat beramiz - mening so'rov matnim asosan qo'shimcha kontekstli janrdir. Men o'zimning yangiligimni shunday saqlayman, chunki men hali ham natijalarim so'nggi filmlarga qarama-qarshi bo'lishini xohlayman.
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)
Ushbu so'rov menga janr bo'yicha ko'proq natijalarni berish uchun chiqarilgan yilni biroz orqaga suradi (quyida).
Kengaytirilgan so'rov menga yanada nozik nazoratni beradi. Men yangilik ustidan nazoratni saqlab qolaman, lekin tavsif, sarlavha va janr uchun qidiruv matnini ham belgilashim va har biriga oʻzimning afzalliklarimga koʻra, quyida (va 19-21 katakchalar ) oʻziga xos vazn belgilashim mumkin.
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)
Oxirgi film natijalarida ayting, men allaqachon ko'rgan filmni topdim va shunga o'xshash narsani ko'rmoqchiman. Faraz qilaylik, menga "Oq Rojdestvo" yoqdi, 1954 yilgi romantik komediya (id = tm16479) qo'shiqchi-raqqosalar mehmonlarni Vermontdagi qiyin mehmonxonaga jalb qilish uchun sahna namoyishi uchun yig'ilishdi. Advanced_query-ga qo'shimcha with_vector
bandini ( movie_id
parametri bilan) qo'shish orqali with_movie_query menga ushbu film (yoki o'zim yoqtirgan har qanday film) yordamida qidirish imkonini beradi va alohida quyi qidiruv so'rovi matni va vaznini barcha nozik nazorat qilish imkonini beradi.
Birinchidan, biz movie_id parametrimizni qo'shamiz:
with_movie_query = advanced_query.with_vector(movie, Param("movie_id"))
Va keyin men boshqa qidiruv soʻrovlarimni boʻsh yoki eng mos boʻlgan narsani, shuningdek, mantiqiy boʻlgan har qanday ogʻirliklarni belgilashim mumkin. Aytaylik, mening birinchi so‘rovim Oq Rojdestvoning sahna ko‘rinishini/guruh jihatini aks ettiruvchi natijalarni beradi ( 24-hujayraga qarang), lekin men ko‘proq oilaga qaratilgan filmni tomosha qilmoqchiman. Natijalarimni kerakli tomonga burish uchun description_query_text ni kiritishim mumkin.
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)
Ammo endi natijalarimni ko'rganimdan so'ng, men ko'proq engil va kulgili narsaga moyil ekanligimni angladim. Keling, mening so'rovimni mos ravishda o'zgartiramiz:
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)
OK, bu natijalar yaxshiroq. Men shulardan birini tanlayman. Popkornni qo'ying!
Superlinked qidiruv sifatini tekshirish, takrorlash va yaxshilashni osonlashtiradi. Yuqorida biz Superlinked kutubxonasidan Netflix singari vektor maydonida semantik qidiruvni amalga oshirish va aniq, tegishli film natijalarini qaytarish uchun qanday foydalanishni ko'rsatib berdik. Shuningdek, biz kerakli natijaga erishgunimizcha natijalarimizni qanday qilib sozlashni, og‘irlik va qidiruv so‘zlarini o‘zgartirishni ko‘rdik.
Endi daftarni o'zingiz sinab ko'ring va nimaga erishishingiz mumkinligini ko'ring!
Tavsiya mexanizmlari kontentni kashf qilish yo‘limizni shakllantirmoqda. Filmlar, musiqa yoki mahsulotlar bo'ladimi, vektor qidiruvi kelajak - va endi sizda o'zingizni yaratish uchun vositalar mavjud.
Muallif: Mór Kapronczay