За место в топе поисковой выдачи, между крупными компаниями постоянно идёт тихая борьба. Особенно это актуально для ритейлеров с тысячами товаров, ведь от позиции в топе напрямую зависит выручка. Есть несколько способов попасть туда и один из них — поработать с метатегами, которые помогают поисковику показать людям наиболее релевантные для них страницы.

Меня зовут Станислав, я дата-сайентист группы Natural Language Processing (NLP) в Samokat.tech и сейчас мы занимаемся умной обработкой текста для одного из наших направлений — маркетплейса. У нас в группе бывают разные задачи и одна из них — автоматизация составления мета-тегов веб-страниц в контексте SEO.

Задача не уникальна и есть множество вариантов её решения. В этой статье расскажу, какой подход выбрали в нашей группе NLP. Надеюсь, этот опыт будет полезен для веб-разработчиков и владельцев сайтов, которые хотят оптимизировать свой контент для поисковых систем.


Это база

Для начала обозначу, что имеется в виду под метатегами.

Метатеги представляют из себя отдельные атрибуты в html-коде веб-страницы. Опираясь на содержание метатегов, поисковик определяет релевантность страниц и ранжирует поисковую выдачу для пользователей. В результате качественно составленные метатеги поднимают страницу в поисковой выдаче и повышают её посещаемость. А чем выше посещаемость — тем больше вероятность, что купят именно у вас. Это один из самых простых способов поднять продажи.

Основными метатегами страницы являются её title (заголовок страницы) и description (описание страницы). Title и description видны как поисковику, так и пользователям, поэтому при их составлении необходимо быть крайне аккуратными.

Конкретный алгоритм, по которому тот или иной поисковик ранжирует выдачу, неизвестен, но при этом наблюдаются некоторые общие закономерности, давно выявленные SEO-специалистами. Для составления эффективного тайтла необходимо учесть следующие нюансы:

  • схожесть c наиболее частотными запросами пользователей, желательно их полное включение в тайтл;

  • наличие ключевых слов, по которым ищут соответствующие страницы;

  • уникальность заданного метатега страницы сайта среди метатегов всех остальных страниц сайта;

  • текст должен быть похож на запрос, сформулированный человеком;

  • начало метатега имеет наибольшее влияние (для тайтла основной вклад вносят примерно первые 12 слов);

  • совпадение содержимого тайтла страницы сайта с её действительным содержимым;

Аналогичные правила действуют и для description, которые, в свою очередь, могут быть более длинными. Для более подробного изучения можно обратиться к следующим статьям: раз, два и три.

Вот, например, пара хороших тайтлов:

купить телефон Xiaomi в Москве, цены на <company name>
Смартфоны Xiaomi - купить телефон Сяоми по ... - <company name>

И один не очень:

Xiaomi телефон - купить недорого - <company name>

Также важно заметить, что помимо роботов, метатеги title и description видны пользователям, поэтому должны представлять из себя действительно осмысленный читаемый текст, который привлекает пользовательское внимание.

Как появилась такая задача

В нашем SEO-отделе уже была автоматизация метатегов, но она работала на шаблонах и никак не учитывала пользовательские запросы. Поэтому «шаблонные» заголовки оставляли для не самых значимых товаров и листингов, а для наиболее важных — заголовки составляли вручную. 

Это работающая схема, в которой составление заголовков уже поставлено на поток. Но компания растёт, и за последний год каталог товаров вырос в несколько раз. Соответственно, возросла и нагрузка на модераторов. Нанять больше людей — не самый эффективный подход, поэтому было решено двигаться в сторону автоматизации, чтобы приблизить качество автоматического составления тегов к ручному.

Вкратце задача заключалась в реализации сервиса, который будет автоматически генерировать title и description для страниц маркетплейса с листингами товаров и отдельными товарами, учитывая основные факторы, на которые модераторы опираются при ручном составлении соответствующих тегов.

Статью я пишу на этапе готовности базовой модели для генерации title листингов товаров. Для начала мы взялись за автоматическую генерацию тайтлов исключительно для листингов товаров, так как их меньше чем отдельных товаров и по ним гораздо дешевле собрать пользовательские запросы.

Автоматическая генерация title

Для составления тайтлов SEO-специалисты используют статистику частотных запросов, по которым ищут соответствующие товары, а также некоторую дополнительную внутреннюю информацию для описания товаров на странице. Из частей наиболее частотных запросов составляются тайтлы, удовлетворяющие критериям, описанным ранее. Статистику по запросам можно получить, используя сторонние сервисы от поисковиков, для Яндекса, например, это wordstat.yandex.

Сервис генерации тайтлов должен выполнять аналогичную seo-специалистам работу, превращая входные данные в виде статистики частотных запросов и дополнительной информации о товаре в тайтл страницы.

Базовый подход

В базовом подходе для составления тайтла мы решили пойти простым путём и вместо генерации из кусков отдельных частотных запросов, решили собрать основу тайтла из 1-ого или 2-х наиболее подходящих пользовательских запросов. Далее подкорректировать её, добавить специфических ключевых слов, чтобы получить полноценный тайтл.

Рассмотрим на примере каталога «Смартфоны Samsung Galaxy»:

Для начала посмотрим на отсортированные по частоте подходящие под категорию пользовательские запросы:

Наиболее популярные запросы:

 ('samsung galaxy', 4393),
 ('купить телефон самсунг', 3622),
 ('самсунг галакси', 2838),
 ('купить смартфон самсунг', 1526),
 ('смартфон самсунг', 1464),
 ('смартфоны самсунг', 1375),
 ('купить смартфон самсунг в москве', 708),
 ('купить самсунг галакси', 641),
 ('смартфон samsung', 458),
 ('купить телефон самсунг галакси', 347),
 ('смартфоны самсунг купить', 283),
 ('смартфон samsung galaxy', 244),
 ('смартфоны samsung', 237),
 ('купить смартфон samsung', 224),
 ('смартфон самсунг галакси', 221),
 ('купить samsung galaxy', 209),
 ('смартфоны самсунг купить в москве', 189),
 ('самсунг смартфоны каталог и цены', 186),
 ('дешевые телефоны самсунг', 141),
 ('смартфоны самсунг цены', 130),

Наименее популярные запросы:

 ('смартфоны самсунг цены в москве недорого', 2),
 ('дешевый телефон самсунг цена', 2),
 ('самсунг галакси дешевый', 2),
 ('смартфоны galaxy', 2),
 ('samsung купить смартфон цены', 2),
 ('модели смартфонов самсунг цены', 2),
 ('смартфоны samsung москва', 2),
 ('смартфон самсунг цена москва', 2),
 ('купить смартфон самсунг в интернет магазине недорого', 2),
 ('смартфон samsung galaxy sm', 2),
 ('смартфоны линейки самсунг', 2),
 ('сколько смартфонов самсунг', 2),
 ('самсунг смартфон купить в москве у официального', 2),
 ('купить смартфон samsung sm', 2),
 ('купить телефон самсунг смартфон', 2),
 ('купить смартфон самсунг рубли', 2)

Тайтл в основном позволяет подниматься в топ поисковой выдачи именно по включенным в него запросам. Таким образом, чтобы получить наибольший охват, необходимо из представленных запросов выбрать такой, что содержат в себе как можно точнее большинство других популярных запросов. Напишем алгоритм для поиска наиболее подходящего запроса.

Опишем алгоритм на конкретном примере

По опыту SEO-специалистов изменение формы слов в тайтле не оказывает сильного влияния на ранжирование в поисковой выдаче, поэтому пересечения будем искать по лемматизированным предложениям. Сопоставим каждому поисковому запросу его же лемматизированное.

Купить кухонный комбайн в интернет магазине недорого в москве \rightarrowкухонный комбайн в интернет магазин недорого в москва

Для лемматизированных предложений будем искать подходящие из представленных выше соображений. Для этого:

  1. Векторизуем предложения с tf-idf, рассматривая в качестве токенов не только отдельные слова, но и n-граммы слов (это позволяет учитывать связи слов), вектора при этом не нормируются (при нормировке затухает влияние токенов в длинных запросах). Обе функции доступны в sklearn реализации tf-idf векторизатора.

  2. Расчитаем скор для каждого запроса в виде суммы s_l = \sum\nolimits_{i} (\vec{x_l},\vec{x_i})w_iгде \vec{x_l}- вектор первых 12 слов запроса, \vec{x_i}- вектор первых 12 слов i-го запроса, w_i- частота i-го запроса. Таким образом скор будет наибольшим для тех запросов, которые достаточно точно сохраняют в себе запросы с большими весами.

В матричном виде расчет скоров для всех запросов можно записать так:

\vec{S} = \hat{X}\hat{X}^T\vec{W}, где \vec{S} - вектор скоров пользовательских запросов,\hat{X}-матрица векторов запросов, \vec{W}- вектор весов запросов;

Для большей наглядности прикреплю код функции расчета скора для всех кандидатов на 1-ю (если diff_vector = None) и 2-ю (если в качестве diff_vector подать первую часть) части тайтла.

Код функции расчета скора для пользовательских запросов:

def calc_all_weights(dict_cat, vectorizer, diff_vector = None):
   X = vectorizer.transform([to_first_normal_form(x) for x in list(dict_cat.keys())]).toarray()
   if diff_vector:
       diff_vector = vectorizer.transform([to_first_normal_form(diff_vector)]).toarray()
       X = X-diff_vector
       X = np.where(X>0, X, 0)
   res = np.dot(np.dot(X,X.T), np.array(list(dict_cat.values())))
   res = Counter(dict([(x,y) for x,y in zip(list(dict_cat.keys()), res)]))
   return dict(res.most_common())

Рассчитаем скоры для всех запросов-кандидатов и выберем запрос с наибольшим скором в качестве начала тайтла:

calc_all_weights(dict_cat, vectorizer, diff_vector = None)
Out[]:
{'купить телефон самсунг галакси': 2159984.81207488,
 'купить смартфон самсунг галакси': 2136268.498054917,
 'купить телефон самсунг смартфон': 1910952.7081585883,
 'купить смартфон самсунг в москве цены': 1906845.0696003735,
 'купить смартфон самсунг в москве': 1888036.120151773,
 'смартфон самсунг галакси купить в москве': 1801821.4318992593,
 'смартфоны самсунг галакси купить': 1740137.2737508924,
 'купить телефон самсунг в москве цены': 1734387.510821999,
  1. В большинстве случаев в тайтл можно включить сразу два запроса, так как по длине они могут быть достаточно короткими и в совокупности включить в первые 12 слов больше популярных запросов. Тогда вторым запросом нужно выбрать такой, что учитывает как можно больше запросов, не учтенных в первой части тайтла. Для этого рассмотрим только положительные компоненты разностей из векторов запросов-кандидатов и вектора запроса, выбранного в качестве начала тайтла.

calc_all_weights(dict_cat, vectorizer, diff_vector = 'купить телефон самсунг галакси')
Out[]:
{'купить смартфон самсунг в москве цены': 1437544.1569455762,
 'купить смартфон самсунг в москве': 1418735.207496976,
 'купить смартфон samsung galaxy': 1382699.419361276,
 'купить смартфон самсунг недорогой но хороший': 1249469.350270875,
 'смартфон samsung galaxy купить в москве': 1213855.8960057737,
 'купить смартфон самсунг галакси': 1208176.5604695233,
 'купить смартфон самсунг недорогой': 1192947.5447259317,
  1. Для обоих вариантов с 1-им и 2-мя запросами составим тайтл по шаблону. Добавим необходимые ключевые слова "цены", "купить", если их нет в выбранных запросах, исключим повторы текста. Векторизуем оба готовых тайтла и выберем вариант с наибольшим скором.

  2. Предварительный тайтл готов.

Купить телефон самсунг галакси - смартфон самсунг в Москве цены в интернет-магазинах на название_компании

Постобработка

Полученные тайтлы должны быть качественными не только для машинной проверки, но и удовлетворять определённым требованиям в связи с тем, что их будут видеть пользователи.

В нашем случае у большинства полученных тайтлов имеются 2 проблемы:

  • Мы составляем тайтлы для коллекций, поэтому вещи, входящие в коллекцию, должны упоминаться в тайтле  во множественном числе. В изначальных запросах обычно это не так. При составлении тайтлов учитывать только запросы  во множественном числе - не лучшая идея, так как полученный тайтл в таком случае будет хуже учитывать популярные пользовательские запросы, чего допускать нельзя;

  • Названия брендов в запросах часто написаны неправильно, транслитом и без учёта верхнего регистра. Это также необходим исправить.

Продолжим править тайтл для коллекции “Смартфоны Samsung Galaxy”, который содержит обе перечисленные проблемы:

Купить телефон самсунг галакси - смартфон самсунг в Москве цены в интернет-магазинах на название_компании

Исправим всё на этапе постобработки.

Перевод во множественное число

Важно, что перевести во множественное число нужно не все слова в запросе, а только те, что связаны с товарами из коллекции. Для перевода ключевых слов во множественное число мы используем библиотеку pymorphy2, а для определения того, какие слова нужно перевести во множественное число и для выбора верной их словоформы будем оценивать согласованность полного предложения. 

Пример кривого исправления:

купить спортивную бутылку для бега \rightarrowкупить спортивные бутылки для бегов

И корректного:

купить спортивную бутылку для бега \rightarrowкупить спортивные бутылки для бега

Согласованность полной фразы можно оценить при помощи перплексии (степень «удивлённости») произвольной языковой модели, предобученной на русскоязычных текстах. Чем ниже перплексия, тем корректнее оставлено предложение (по мнению языковой модели). Чтобы мнение языковой модели совпадало с человеческим в этом вопросе, стоит подобрать такую, которая достаточно хорошо разбирается в человеческом языке!

В качестве языковой модели сравнивались несколько русскоязычных трансформеров энкодеров, а итоговый выбор пал на небольшую rubert-tiny2 от cointegrated, так как для решаемой задачи она выигрывала в скорости, не отставая по качеству от конкурентов .

Алгоритм действий:

  • Предложение токенизируется по словам;

  • Для каждого слова при помощи pymorphy2 составляются всевозможные формы независимо от контекста;

  • Составляются предложения из всевозможных комбинаций слов в единственном и множественном числах;

  • А тут происходит магия. К каждому предложению прибавляются соответствующие суффикс и префикс, которые должны показать языковой модели, что вещи из коллекции, о которых идёт речь, должны быть употреблены во множественном числе. В настоящей реализации в конец дописывается «качественные оптом», в начало «Все». Если в запросе есть слово «купить», то "все" добавляется после него;

Посмотрим как будут выглядеть предложения после добавления соответствующих префикса и суффикса:

Купить телефон самсунг галакси \rightarrowКупить все телефон самсунг галакси, качественные оптом

Купить телефоны самсунг галакси \rightarrowКупить все телефоны самсунг галакси, качественные оптом

Заметно, что в данном примере, множественное число в предложении выглядит правильнее, что и должна заметить языковая модель.

  • Для каждого из полученных предложений рассчитывается perplexity выбранной языковой модели. Выбирается вариант с наименьшей perplexity.

[('купить телефоны самсунг галакси', 1204.9041649310993),
 ('купить телефоны самсунги галакси', 1639.3338510855972),
 ('купить телефоны самсунг галаксите', 3220.609224903253),
 ('купить телефон самсунг галакси', 3602.012820571245),
 ('купить телефоны самсунг галаксь', 4118.81731829573),
 ('купить телефоны самсунги галаксите', 4410.842122054276),
 ('купить телефоны самсунги галаксь', 5042.7952879331315),
 ('купить телефон самсунги галакси', 6154.057301289677),
 ('купить телефон самсунг галаксите', 9347.090134432183),
 ('купить телефон самсунг галаксь', 12610.902656272176)]

Как и ожидалось, наименьшему значению перплексии соответствует желаемый вариант с исправлением «телефон» \rightarrow«телефоны».

В теории ускорить поиск наиболее подходящего варианта можно с применением приблизительных методов дискретной оптимизации (например, использовать Симуляцию Отжига) вместо полного перебора. Недостатком такого подхода является его «приблизительность»/недетерминированность, ввиду чего может быть найдено не оптимальное решение, а лишь близкое к нему. Неточности в тайтле нас не устраивают, к тому же для генерации тайтлов запросы обычно достаточно короткие, перебирать приходится в среднем менее 64 вариантов на предложение и с использованием небольшой модели вроде rubert-tiny2 даже без видеокарты тайтл в среднем обрабатывается менее чем за 1 секунду. В результате нет необходимости жертвовать качеством решения для ускорения его поиска.

Корректировка написания бренда

В задаче исправления написания бренда важным моментом является то, что для каждой коллекции известен используемый бренд. Это значительно упрощает решение и позволяет использовать векторный поиск, по известному бренду. Далее рассмотрим различные варианты:

  1. Если оригинальное название бренда записывается кириллицей, тогда всё просто. Векторизуем название бренда с помощью tf-idf, аналогичным образом векторизуем n-граммы слов запроса (n-граммы используются, т.к. название бренда может состоять из нескольких слов и, более того, не совпадать с пользовательским запросом по количеству слов). Далее, найдём наиболее близкие по косинусному расстоянию вектора и заменим соответствующий n-грамм в запросе на оригинальное название бренда.

  2. Если же в оригинале бренд записывается на латинице, то:

    а) Если в пользовательском запросе тоже есть слова на латинице, то соответствующий n-грамм можно смело заменять на название оригинального бренда.

    б) Если же в пользовательском запросе нет латиницы, значит название бренда написано транслитом. В таком случае необходимо сопоставить оригинальное название бренда с его транслитерацией в пользовательском запросе. При этом побуквенная транслитерация даёт совсем далёкие от правды результаты, а готовых предобученных text2text моделей транслитерации текста в открытом доступе я не нашёл, поэтому пришлось искать данные для обучения и обучать модель самостоятельно.

Для решения данного кейса была обучена простая нейросеть вида энкодер-декодер преобразующая tf-idf вектор по n-граммам символов в tf-idf вектор его транслитерации. В данной реализации в качестве автокодировщика использовалась простая полносвязная нейросеть. Здесь можно было бы обучить любую более продвинутую нейросеть вплоть до трансформеров, да и текст векторизовать при её же помощи, но такой подход требует больше тренировочных данных, достать которые не удалось.

Датасет для обучения нейросети был собран из внутренних данных компании в основном из сопоставления карточек товаров мерчантов с карточками товаров на маркетплейсе (мерчанты часто записывают название бренда транслитом или не совсем верно, что даёт возможность собрать пары Бренд-транслитерация для части товаров из каталога маркетплейса). Также часть транслитераций была собрана из пользовательских запросов статистическими методами.

В итоге с использованием автокодировщика для англоязычных брендов задача решается аналогичным образом с добавлением промежуточного пункта преобразования вектора бренда в вектор его транслитерации.

Найденный n-грамм заменяется на оригинальное название бренда.

Замена на верное написание бренда и множественное число при использовании 2-х запросов производится только в 1-м включении для разбавления тайтла различными словоформами. Во втором включении изменяется только регистр на заглавную букву.

Итог для данного тайтла:

для 1-й части происходит замена:

Купить телефоны самсунг галакси \rightarrowКупить телефоны Samsung Galaxy

Для 2-й части происходит замена:

смартфоны cамсунг в Москве \rightarrowсмартфоны Самсунг в Москве

Все это записывается обратно в один тайтл:

Купить телефоны Samsung Galaxy - смартфоны Самсунг в Москве, цены в интернет-магазинах на  название_компании

Что получилось в итоге

На момент написания статьи у нас алгоритм, который работает как сервис для модераторов. Алгоритм генерирует title для листингов товаров, анализируя SEO-запросы и название товара. Схема работает с ручной модерацией (особое внимание уделяется сгенерированным тайтлам с высокой перплексией) — это помогает одновременно облегчить работу модераторов и продолжить обучение моделей.  

Модераторы либо добавляют сгенерированный алгоритмом тайтл к веб-странице без изменений, либо вносят исправления и записывают свои комментарии, квалифицирующие проблему. Следующим шагом комментарии используются для аналитики существующих проблем и модернизации алгоритмов на её основе.

Дальше планируем дорабатывать алгоритмы и приниматься за задачу генерации title для отдельных товаров, а также добавлять генерацию description. Для этого придётся использовать принципиально другие подходы, о которых я, возможно, напишу в следующей статье.

Буду признателен за обратную связь от коллег по сфере в комментариях.

Комментарии (0)