→ → Что, если ваш интернет-магазин знал, чего хочет клиент, прежде чем он это сделает? Что, если ваш интернет-магазин знал, чего хочет клиент, прежде чем он это сделает? они предлагают «популярные» или «подобные» элементы на основе ограниченных, устаревших данных. когда пользователи новые (проблема холодного старта), и они редко адаптируются достаточно быстро, когда предпочтения пользователя меняются в режиме реального времени. Most recommendation engines are like helpful but slightly clueless assistants: struggle Но что если ваша система может как маркетолог — сочетание статических данных о продуктах и поведения пользователей в режиме реального времени В нужное время? На самом деле думать Правильные предметы На самом деле думать Использование , который преодолевает эти традиционные недостатки, превращая ваши данные в действующие, эволюционирующие пользовательские профили с использованием векторной инфраструктуры. This guide walks you through building a modern recommendation engine Superlinked (Хотите прыгнуть прямо к коду? Проверьте код с открытым исходным кодом на GitHub здесь. Готовы попробовать системы рекомендующих для вашего собственного использования? Получите демо здесь.) здесь здесь здесь здесь Вы также можете следовать вместе с инструкцией в браузере с нашим Колледж Тл; Др : Большинство рекомендаций для электронной коммерции либо слишком статичны (на основе правил), либо слишком черные ящики (ошибочные модели ML).Superlinked предлагает средний путь: гибкие рекомендации в режиме реального времени, которые могут адаптироваться к пользователям холодного старта, объединяя метаданные с живым поведением — все без переподготовки моделей ML. Достижение персонализации, несмотря на проблемы встраивания векторов RecSys В то время как встраивания векторов могут значительно улучшить системы рекомендаций, их эффективное внедрение требует решения нескольких задач, включая: → → → → Качество и актуальность: Процесс генерации встраивания, архитектура и данные должны быть тщательно рассмотрены. Слабые и шумные данные: встраивания менее эффективны, когда они имеют неполный или шумный ввод. Эффективные методы для больших наборов данных необходимы; в противном случае латентность будет проблемой. Superlinked позволяет решить эти проблемы, объединив все имеющиеся данные о пользователях и продуктах в богатые мультимодальные векторы.В нашем примере электронной коммерции RecSys ниже мы делаем это с помощью следующих элементов библиотеки Superlinked: → → → → → min_max номера Пространства: для понимания отзывов клиентов и информации о ценах текстовое сходство Пространство: для семантического понимания информации о продукте Схема событий и эффекты для изменения векторов Временные весы запроса — для определения того, как вы хотите, чтобы данные обрабатывались при выполнении запроса, что позволяет оптимизировать и масштабировать без повторного встраивания всего набора данных (задержка). Встраивая наши первоначально редкие пользовательские данные (первоначальные предпочтения продукта пользователя), мы можем справиться с проблемой холодного старта. - персонализация рекомендаций, встраивая данные этого события, создавая цикл обратной связи, который позволяет вам обновлять векторы с пользовательскими предпочтениями в режиме реального времени.Кроме того, весы времени запроса Superlinked позволяют тонко настроить результаты поиска, упреждая их, чтобы соответствовать конкретным предпочтениям пользователя. гипер Let's get started! Создание системы рекомендаций для электронной коммерции с помощью Superlinked В начале разработки мы имеем следующее : → product data → → → → → → Количество рецензентов Рейтинги продукции Текстовое описание Название продукта (обычно содержит название бренда) Категория У нас также есть следующее : → data about users and products → → → каждый пользователь выбирает один из трех предлагаемых продуктов при регистрации (т.е. данные о предпочтениях продуктов) поведение пользователя (после регистрации) предоставляет дополнительные данные о событиях – предпочтения по текстовым характеристикам продуктов (описание, название, категория) Также классическая экономика говорит нам, что в среднем все пользователи ceteris paribus предпочитают продукты, которые: → → → → Стоит меньше Есть много отзывов Иметь более высокие рейтинги Мы можем настроить наши пространства, чтобы учитывать эти данные, так что наши RecSys работают в сценариях холодного старта - рекомендуя предметы для пользователей, о которых мы знаем очень мало.После того как наши RecSys запущены и запущены, у нас также будут данные о поведении: пользователи будут нажимать на определенные продукты, покупать определенные продукты и т. Д. Мы можем захватить и использовать эти данные событий для создания откликов, обновления наших векторов, чтобы отразить предпочтения пользователей и улучшить качество рекомендаций. Создание Superlinked Для начала необходимо установить библиотеку Superlinked и импортировать классы. %pip install superlinked==6.0.0 import altair as alt import os import pandas as pd import sys from superlinked.framework.common.embedding.number_embedding import Mode from superlinked.framework.common.schema.schema import schema from superlinked.framework.common.schema.event_schema import event_schema from superlinked.framework.common.schema.schema_object import String, Integer from superlinked.framework.common.schema.schema_reference import SchemaReference 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.index.effect import Effect from superlinked.framework.dsl.query.param import Param from superlinked.framework.dsl.query.query import Query 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.number_space import NumberSpace alt.renderers.enable(get_altair_renderer()) pd.set_option("display.max_colwidth", 190) Мы также определяем наши наборы данных и создаем константу для хранения топ-10 элементов - см. В ноутбуке Клетка 3 Теперь, когда установлены библиотеки, импортированы классы и определены места набора данных, мы можем взглянуть на наш набор данных, чтобы проинформировать вас о том, как мы настраиваем наши пространства. # the user preferences come from the user being prompted to select a product out of 3 - those will be the initial preferences # this is done in order to give somewhat personalised recommendations user_df: pd.DataFrame = pd.read_json(USER_DATASET_URL) user_df Мы также можем установить тщательный осмотр данных о распределении наших продуктов - см. Это дает вам представление о том, сколько продуктов находятся в разных ценовых точках, имеют разные оценки и имеют разные рейтинги (включая то, где большинство продуктов находятся в этих диапазонах). Клетка 5 Цены на продукты в основном ниже 1000$. Мы можем настроить диапазон пространства на 25-1000, чтобы сделать его представительным, не искаженным внешними значениями. Количество отзывов о продуктах равномерно распределено, а рейтинги отзывов относительно равномерно распределены, поэтому дополнительная обработка не требуется. . . Клетки 7-9 Создание индекса для векторного поиска Библиотека Superlinked содержит набор основных строительных блоков, которые мы используем для построения индекса и управления поиском. . . здесь Давайте поставим строительные блоки этой библиотеки для использования в нашем EComm RecSys. чтобы сообщить системе о ваших данных. define your Schema # schema is the way to describe the input data flowing into our system - in a typed manner @schema class ProductSchema: description: String name: String category: String price: Integer review_count: Integer review_rating: Integer id: IdField @schema class UserSchema: preference_description: String preference_name: String preference_category: String id: IdField @event_schema class EventSchema: product: SchemaReference[ProductSchema] user: SchemaReference[UserSchema] event_type: String id: IdField # we instantiate schemas as follows product = ProductSchema() user = UserSchema() event = EventSchema() Далее вы используете пространства, чтобы сказать, как вы хотите обрабатывать каждую часть данных при встраивании. В определениях пространства мы описываем, как встраивать входы, чтобы они отражали семантические отношения в наших данных.Каждое пространство оптимизировано для встраивания данных, чтобы вернуть наивысшее возможное качество результатов поиска. # textual inputs are embedded in a text similarity space powered by a sentence_transformers model description_space = TextSimilaritySpace( text=[user.preference_description, product.description], model="sentence-transformers/all-distilroberta-v1", ) name_space = TextSimilaritySpace( text=[user.preference_name, product.name], model="sentence-transformers/all-distilroberta-v1", ) category_space = TextSimilaritySpace( text=[user.preference_category, product.category], model="sentence-transformers/all-distilroberta-v1", ) # NumberSpaces encode numeric input in special ways to reflect a relationship # here we express relationships to price (lower the better), or ratings and review counts (more/higher the better) price_space = NumberSpace( number=product.price, mode=Mode.MINIMUM, min_value=25, max_value=1000 ) review_count_space = NumberSpace( number=product.review_count, mode=Mode.MAXIMUM, min_value=0, max_value=100 ) review_rating_space = NumberSpace( number=product.review_rating, mode=Mode.MAXIMUM, min_value=0, max_value=4 ) # create the index using the defined spaces product_index = Index( spaces=[ description_space, name_space, category_space, price_space, review_count_space, review_rating_space, ] ) # parse our data into the schemas - not matching column names can be conformed to schemas using the mapping parameter product_df_parser = DataFrameParser(schema=product) user_df_parser = DataFrameParser( schema=user, mapping={user.preference_description: "preference_desc"} ) # setup our application source_product: InMemorySource = InMemorySource(product, parser=product_df_parser) source_user: InMemorySource = InMemorySource(user, parser=user_df_parser) executor: InMemoryExecutor = InMemoryExecutor( sources=[source_product, source_user], indices=[product_index] ) app: InMemoryApp = executor.run() # load the actual data into our system source_product.put([products_df]) source_user.put([user_df]) Теперь, когда ваши данные определены в пространствах, вы готовы играть с вашими данными и оптимизировать результаты. Наше решение для холодного старта. Что можно сделать без событий Решение проблемы холодного старта RecSys Здесь мы определяем пользовательский запрос, который использует только вектор предпочтений пользователя.У нас есть конфигурационный контроль над значением (весами) каждого типа ввода (пространства). user_query = ( Query( product_index, weights={ description_space: Param("description_weight"), name_space: Param("name_weight"), category_space: Param("category_weight"), price_space: Param("price_weight"), review_count_space: Param("review_count_weight"), review_rating_space: Param("review_rating_weight"), }, ) .find(product) .with_vector(user, Param("user_id")) .limit(Param("limit")) ) # simple recommendations for our user_1 # these are based only on the initial product the user chose when first entering our site simple_result = app.query( user_query, user_id="user_1", description_weight=1, name_weight=1, category_weight=1, price_weight=1, review_count_weight=1, review_rating_weight=1, limit=TOP_N, ) simple_result.to_pandas() Результаты этого запроса отражают тот факт, что user_1 выбрал сумку, когда они впервые зарегистрировались на нашем сайте ecomm. Также можно рекомендовать продукты пользователю_1, которые привлекательные - то есть, основываясь на их низкой цене, и имея много хороших отзывов. Наши результаты теперь будут отражать как выбор продукта user_1 при регистрации общая популярность продуктов. (Мы также можем играть с этими весами, чтобы исказить результаты в направлении одного пространства или другого.) В целом и general_result = app.query( user_query, user_id="user_1", description_weight=0, name_weight=0, category_weight=0, price_weight=1, review_count_weight=1, review_rating_weight=1, limit=TOP_N, ) general_result.to_pandas() Поиск нового пользователя вводит текст запроса в качестве ввода для наших результатов рекомендаций - см. . . Клетка 20 В нашем примере пользователь_1 искал "костюмы для женщин".Мы можем оптимизировать наши результаты, предоставляя (на ), чтобы порекомендовать больше продуктов «женская одежда куртки». additional weight to the category space category_weight = 10 women_cat_result = app.query( search_query, user_id="user_1", query_text="women clothing jackets", description_weight=1, name_weight=1, category_weight=10, price_weight=1, review_count_weight=1, review_rating_weight=1, limit=TOP_N, ) women_cat_result.to_pandas() Наша дополнительная категория взвешивания производит больше результатов женской одежды. Мы также можем отклонить наши рекомендации к высокооцененным продуктам ( Результаты теперь отражают первоначальное предпочтение пользователя_1 для сумок и предметов, которые обычно популярны, в то время как продукты с низкими рейтингами удаляются полностью. . . review_rating_weight=5 Клетка 22 Использование данных о событиях для создания персонализированных опытов Наши пользователи взаимодействовали с нашей платформой - user_1 больше, user_2 меньше. (см. ниже), представленные как события: behavioral data → → → пользователь, заинтересованный в случайных и досуговых продуктах (user_2) пользователь, заинтересованный в элегантных продуктах для выхода на улицу и формальных рабочих мероприятий (user_1) events_df = ( pd.read_json(EVENT_DATASET_URL) .reset_index() .rename(columns={"index": "id"}) .head(NROWS) ) events_df = events_df.merge( products_df[["id"]], left_on="product", right_on="id", suffixes=("", "r") ).drop("idr", axis=1) events_df = events_df.assign(created_at=1715439600) events_df Давайте взвесим конкретные действия, чтобы зарегистрировать уровень интереса пользователя к конкретному продукту, и скорректируем настройки, чтобы учитывать события при выполнении поиска. event_weights = { "clicked_on": 0.2, "buy": 1, "put_to_cart": 0.5, "removed_from_cart": -0.5, } # adjust the setup to events product_index_with_events = Index( spaces=[ description_space, category_space, name_space, price_space, review_count_space, review_rating_space, ], effects=[ Effect( description_space, event.user, event_weight * event.product, event.event_type == event_type, ) for event_type, event_weight in event_weights.items() ] + [ Effect( category_space, event.user, event_weight * event.product, event.event_type == event_type, ) for event_type, event_weight in event_weights.items() ] + [ Effect( name_space, event.user, event_weight * event.product, event.event_type == event_type, ) for event_type, event_weight in event_weights.items() ], ) event_df_parser: DataFrameParser = DataFrameParser(schema=event) source_event: InMemorySource = InMemorySource(schema=event, parser=event_df_parser) executor_with_events: InMemoryExecutor = InMemoryExecutor( sources=[source_product, source_user, source_event], indices=[product_index_with_events], ) app_with_events: InMemoryApp = executor_with_events.run() Теперь мы создаем новый индекс для учета событий пользователей, а затем персонализируем рекомендации каждому пользователю соответственно. # for a new index, all data has to be put into the source again source_product.put([products_df]) source_user.put([user_df]) source_event.put([events_df]) # a query only searching with the user's vector the preferences are now much more personalised thanks to the events personalised_query = ( Query( product_index_with_events, weights={ description_space: Param("description_weight"), category_space: Param("category_weight"), name_space: Param("name_weight"), price_space: Param("price_weight"), review_count_space: Param("review_count_weight"), review_rating_space: Param("review_rating_weight"), }, ) .find(product) .with_vector(user, Param("user_id")) .limit(Param("limit")) ) Мы можем наблюдать влияние включения событий в наши RecSys, взвешивая персонализацию или Во-первых, давайте рассмотрим эффект (по сравнению с исходной линией) взвешивания промежутков, на которые влияют эти (поведенческие данные) события. Только слегка Тяжело # with small weight on event-affected spaces, we mainly just alter the results below position 4 general_event_result = app_with_events.query( personalised_query, user_id="user_1", description_weight=1, category_weight=1, name_weight=1, price_weight=1, review_count_weight=1, review_rating_weight=1, limit=TOP_N, ) general_event_result.to_pandas().join( simple_result.to_pandas(), lsuffix="", rsuffix="_base" )[["description", "id", "description_base", "id_base"]] С очень малой нагрузкой на пространства, затронутые событиями, мы наблюдаем изменение, но в основном только в последней половине нашего топ-10 по сравнению с предыдущими результатами («id_base», справа). Но если мы более серьезно взвесим пространства, затрагиваемые событиями, то в нашем списке рекомендаций мы увидим совершенно новые элементы. # with larger weight on the the event-affected spaces, more totally new items appear in the TOP10 event_weighted_result = app_with_events.query( personalised_query, user_id="user_1", query_text="", description_weight=5, category_weight=1, name_weight=1, price_weight=1, review_count_weight=1, review_rating_weight=1, limit=TOP_N, ) event_weighted_result.to_pandas().join( simple_result.to_pandas(), lsuffix="", rsuffix="_base" )[["description", "id", "description_base", "id_base"]] Мы также можем, конечно, использовать весы для персонализации наших рекомендаций на основе поведения конкретного пользователя (данные о событиях) и В частности, цена (см. ) одновременно отдавать приоритет другим атрибутам продукта Клетка 31 Заключение Реализация eComm RecSys библиотеки Superlinked (выше) показывает вам, как реализовать мощь встраиваний векторов, включая семантический смысл запросов пользователей и поведенческих данных.Используя наши пространства числа и текстового сходства min_max, схему событий и эффекты, а также весы времени запросов, вы можете решить проблемы холодного старта, качества и актуальности и масштабируемости RecSys и предоставить высокоточные, пользовательские рекомендации в производстве. Теперь ваша очередь! . . Попробуйте реализовать библиотеку Superlinked самостоятельно с помощью нашего ноутбука Try It Yourself – Get the Code & Demo! Попробуйте сами – получите код и демо! → → → Загрузите код: ознакомьтесь с полной реализацией в нашем репо GitHub здесь.Форкируйте его, настройте и сделайте его своим! See It in Action: Хотите увидеть, как это работает в реальном мире? Забронируйте быстрое демо, и исследуйте, как Superlinked может перезарядить ваши рекомендации. здесь здесь . . Рекомендационные двигатели формируют то, как мы находим контент, будь то популярные брюки, музыка или другие продукты. — и теперь у вас есть инструменты, чтобы создать свой собственный. vector search is the future