телевизори. Конзоли. Проектори и аксесоари. Технологии. Цифрова телевизия

PINQ - Запитани набори от данни. Фасетно търсене. Как да изградите фасетно търсене с помощта на фасетни броячи? Предимства на фасетното търсене

Разгледахме набързо инсталацията и основния синтаксис на PINQ, порт на LINQ към PHP. В тази статия ще разгледаме как да използваме PINQ за симулиране на функцията за фасетно търсене в MySQL.

В тази статия няма да покрием всички аспекти на фасетното търсене. Желаещите могат да потърсят подходяща информация в интернет.

Типичното фасетно търсене работи по следния начин:

  • Потребителят въвежда ключова дума или няколко ключови думиЗа търсене. Например „рутер“ за търсене на продукти, в които думата „рутер“ се появява в описанието, ключовите думи, името на категорията, таговете и т.н.
  • Сайтът връща списък с продукти, които отговарят на тези критерии.
  • Сайтът предоставя няколко връзки за персонализиране на вашите думи за търсене. Например, може да ви позволи да посочите конкретни производители на рутери или да зададете ценови диапазон или други функции.
  • Потребителят може да продължи да задава допълнителни критерии за търсене, за да получи набора от данни, който представлява интерес.

Фасетираното търсене е доста популярно и мощен инструмент, който може да се види на почти всеки уебсайт за електронна търговия.

За съжаление фасетираното търсене не е вградено в MySQL. И така, какво трябва да направим, ако все още използваме MySQL, но искаме да дадем на потребителя тази възможност?

С PINQ, който има подобен, мощен и прост подход, можем да постигнем същото поведение, както ако използваме други машини за бази данни.

Разширяване на демото от първата част

Коментирайте: Целият код от тази част и от първата част може да бъде намерен в хранилището.

В тази статия ще разширим демонстрацията от част 1 със значително подобрение под формата на фасетно търсене.

Нека започнем с index.php и добавим следните редове към него:

$app->get("demo2", function () use ($app) ( global $demo; $test2 = new pinqDemo\Demo($app); return $test2->test2($app, $demo->test1 ($приложение)); )); $app->get("demo2/facet/(key)/(value)", function ($key, $value) use ($app) ( global $demo; $test3 = new pinqDemo\Demo($app); връща $test3->test3($app, $demo->test1($app), $key, $value); ));

Първият маршрут ни отвежда до страница за преглед на всички публикации, които отговарят на търсенето по ключова дума. За да запазим примера прост, избираме всички книги от таблицата book_book. Той също така ще покаже получения набор от данни и набор от връзки за определяне на критериите за търсене.

В реални приложения, след щракване върху такива връзки, всички филтри за аспекти ще се приспособят към граничните стойности на получения набор от данни. Така потребителят ще може последователно да добавя нови условия за търсене, например първо да избере производител, след това да посочи ценови диапазон и т.н.

Но в този пример няма да приложим това поведение - всички филтри ще отразяват граничните стойности на оригиналния набор от данни. Това е първото ограничение и първият кандидат за подобрение в нашата демонстрация.

Както можете да видите в кода по-горе, действителните функции се намират в друг файл, наречен pinqDemo.php. Нека да разгледаме съответния код, който предоставя функцията за фасетно търсене.

Аспектен клас

Първата стъпка е да създадете клас, който представлява аспект. Като цяло един аспект трябва да съдържа няколко свойства:

  • Данните, с които работи ( $данни)
  • Ключът, по който се извършва групирането ( $ключ)
  • Тип ключ ($type). Може да бъде едно от следните:
    • посочете пълния низ за точно съвпадение
    • посочете част от низа (обикновено началната) за търсене по шаблон
    • посочете диапазон от стойности за групиране по диапазон
  • ако типът ключ е диапазон от стойности, трябва да дефинирате стъпка на стойността, за да определите долната и горната граница на диапазона; или ако типът е част от низ, трябва да посочите колко първи букви ще се използват за групиране ($range)

Групиране- най-критичната част от аспекта. Цялата обобщена информация, която даден аспект може да върне, зависи от критериите за групиране. Обикновено най-използваните критерии за търсене са „Пълен низ“, „Част от низ“ или „Диапазон от стойности“.

Пространство от имена classFacet ( използвайте Pinq\ITraversable, Pinq\Traversable; class Facet ( public $data; // Оригинален набор от данни public $key; // поле, по което да групирате public $type; // F: цял ред; S: начални низове ; R: диапазон; обществен $ диапазон; // играе роля само ако $type != F ... публична функция getFacet() ( $filter = ""; if ($this->type == "F") / / цял ред ( ... ) elseif ($this->type == "S") // начало на ред ( ... ) elseif ($this->type == "R") // диапазон от стойности ​( $ filter = $this->data ->groupBy(function($row) ( return floor($row[$this->key] / $this->range) * $this->range; )) -> select(function (ITraversable $data) ( return ["key" => $data->last()[$this->key], "count" => $data->count()]; )); ) return $филтър; ) ) )

Основната функция на този клас е да върне филтриран набор от данни въз основа на оригиналния набор от данни и свойства на аспекта. От кода става ясно, че за различни видовесе използват сметки различни начинигрупиране на данни. В кода по-горе показахме как може да изглежда кодът, ако групираме данните по диапазон от стойности на стъпки, посочени в $ диапазон.

Задаване на аспекти и показване на изходни данни

Публична функция test2($app, $data) ( $facet = $this->getFacet($data); return $app["twig"]->render("demo2.html.twig", array("facet" = > $facet, "data" => $data)); ) частна функция getFacet($originalData) ( $facet = array(); $data = \Pinq\Traversable::from($originalData); // 3 примера за създаване различни аспектни обекти и връща аспектите $filter1 = нов \classFacet\Facet($data, "author", "F"); $filter2 = нов \classFacet\Facet($data, "title", "S", 6 ); $filter3 = new \classFacet\Facet($data, "price", "R", 10); $facet[$filter1->key] = $filter1->getFacet(); $facet[$filter2-> ключ ] = $filter2->getFacet(); $facet[$filter3->key] = $filter3->getFacet(); return $facet; )

В метода getFacet() правим следното:

  • Преобразувайте оригиналните данни в Pinq\Traversable обект за по-нататъшна обработка
  • Създаваме три аспекта. Аспектът „автор“ ще групира по полето за автор и ще приложи групиране по целия ред; аспект 'title' - по полето за заглавие с групиране по част от реда (по първите 6 знака); аспект 'цена' - по ценовото поле с групиране по диапазон (на стъпки от 10)
  • Накрая извличаме аспектите и ги връщаме на функцията test2, така че да могат да бъдат изведени в шаблона за показване

Извеждане на аспекти и филтрирани данни

В повечето случаи филтрите ще се показват като линия и ще ви отведат до преглед на филтрирания резултат.

Вече създадохме маршрут ("demo2/facet/(key)/(value)") за показване на фасетирани резултати от търсене и филтриране на връзки.

Маршрутът приема два параметъра в зависимост от ключа, по който се филтрира, и стойността за този ключ. Функцията test3, която е обвързана с този маршрут, е показана по-долу:

Публична функция test3($app, $originalData, $key, $value) ( ​​​​$data = \Pinq\Traversable::from($originalData); $facet = $this->getFacet($data); $filter = null; if ($key == "author") ( $filter = $data ->where(function($row) use ($value) ( ​​​​return $row["author"] == $value; )) ->orderByAscending( function($row) use ($key) ( return $row["price"]; )) ; ) elseif ($key == "price") ( ... ) else //$key== title ( .. . ) return $app["twig"]->render("demo2.html.twig", array("facet" => $facet, "data" => $filter)); )

По принцип, в зависимост от ключа, прилагаме филтриране (анонимна функция в оператора where) според предадената стойност и получаваме следния набор от филтрирани данни. Можем също да зададем реда на филтриране на данни.

Накрая показваме необработените данни (заедно с филтрите) в шаблона. Този маршрут използва същия модел, който използвахме в "demo2".

Лента за търсене

    (% за k, v във фасет %)
  • ((k|главна буква))
    • (% за vv във v %)
    • ((vv.count))((vv.key))
    • (%endfor%)
    (%endfor%)

Трябва да помним, че аспектите, генерирани от нашето приложение, са вложени масиви. На първо ниво това е масив от всички аспекти, като в нашия случай те са три (съответно за автор, заглавие, цена).

Всеки аспект има масив ключ-стойност, така че можем да итерираме върху него, използвайки нормални методи.

Забележете как създаваме URL адресите за нашите връзки. Ние използваме както външния ключ на цикъл (k), така и ключовете на вътрешния цикъл (vv.key) като параметри за маршрута ("demo2/facet/(key)/(value)"). Размерът на масивите (vv.count) се използва за показване в шаблона.

Първото изображение показва оригиналния набор от данни, а второто изображение е филтрирано по ценови диапазон от $0 до $10 и сортирано по автор.

Страхотно, успяхме да симулираме фасетно търсене в нашето приложение!

Преди да завършим тази статия, трябва да разгледаме окончателно нашия пример и да определим какво може да бъде подобрено и какви ограничения имаме.

Възможни подобрения

Като цяло това е много елементарен пример. Току-що прегледахме основния синтаксис и концепции и ги внедрихме като работещ пример. Както беше посочено по-рано, имаме няколко области, които могат да бъдат подобрени за по-голяма гъвкавост.

Трябва да приложим критерии за търсене с „наслагване“, тъй като настоящият пример ни ограничава до възможността да прилагаме филтриране при търсене само към оригиналния набор от данни; не можем да приложим фасетно търсене към вече филтриран резултат. Това е най-голямото подобрение, което мога да си представя.

Ограничения

Търсенето на аспекти, реализирано в тази статия, има сериозни ограничения (които може да се отнасят и за други реализации на търсене на аспекти):

Извличаме данни от MySQL всеки път

Това приложение използва рамката Silex. Като всяка рамка с една входна точка като Silex, Symfony, Laravel, нейният файл index.php (или app.php) се извиква всеки път, когато се анализира маршрут и се изпълняват функции на контролера.

Ако погледнете кода в нашия index.php, ще забележите, че следният ред код:

$demo = нов pinqDemo\Demo($app);

се извиква всеки път, когато се визуализира страницата на приложението, което означава, че следните редове код се изпълняват всеки път:

Демонстрация на клас ( private $books = ""; public function __construct($app) ( $sql = "select * from book_book order by id"; $this->books = $app["db"]->fetchAll($sql );)

Ще бъде ли по-добре, ако не използваме рамка? Е, въпреки факта, че разработването на приложения без рамки не е добра идея, мога да кажа, че ще срещнем същите проблеми: данните (и състоянието) не се запазват между различните HTTP заявки. Това е основна характеристика на HTTP. Това може да се избегне чрез използване на механизми за кеширане.

Спестихме малко SQL заявкиизползване на аспекти. Вместо да подадем една заявка за избор за извличане на данните и три заявки за групиране със съответните клаузи where, ние изпълнихме само една заявка where и използвахме PINQ, за да получим обобщената информация.

Заключение

В тази част внедрихме възможността за фасетно търсене в колекция от книги. Както казах, това е само малък пример, който има място за подобрение и който има редица ограничения.

Интелигентен филтър или фасетно търсене е филтър по продуктова категория, който може да се види в големи онлайн магазини и същия Yandex.market. Помага за последователно сортиране на продукти със свойствата, от които се нуждае потребителят, като елиминира всичко ненужно. Това е много удобна опция, която ви позволява бързо да намерите желания продукт или материал на сайта.

И така, нека да преминем директно към инсталирането и конфигурирането на модулите, от които се нуждаем

Първо ще трябва да изтеглим и инсталираме следните модули: API за търсене, API за търсене в база данни, API за обекти и изгледи.

На страницата с модули разрешаваме:

  • API за търсене
  • Търсете изгледи
  • Търсене в база данни
  • API на обекта
  • Изгледи
  • Изгледи UI
  • Ctools

Създаване на сървър за търсене

Хайде да отидем до Конфигурация > Търсене и метаданни > API за търсене(/admin/config/search/search_api) и щракнете Добавете сървър.
След това въведете името на сървъра в падащия списък Клас на обслужванеизбирам Услуга за база даннии запазете.

Създаване на индекс

Хайде да отидем до Конфигурация > Търсене и метаданни > API за търсене(/admin/config/search/search_api), щракнете Добавете сървър (Добавете индекс).
Въведете името на индекса в полето Тип артикул (тип артикул)изберете " Материал“, в полето сървъризбирам Сървър за база данни, щракнете Създаване на индекс.


Във формата, която се отваря, поставете отметки в квадратчетата, по които ще се извърши сортирането и запазете.
За да можете да сортирате по име на възел, включете заглавието и изберете типа срещу него в падащия списък низ, но не пълен текст. Не можете да сортирате по пълен текст.

В следващата форма, която се отваря Филтри(работен процес) Оставих всичко по подразбиране, отидете на раздела Преглед (Статус), и натиснете Индексирайте сега (Индексирайте сега).
След като индексирането приключи, ще създадем страница за търсене.

Създаване на страница за търсене

Хайде да отидем до Структура > Изгледии щракнете Добавете нов изглед (Добавете нов изглед).
В новия изглед в падащия списък Покажи (Покажи)изберете индекса, който по-рано създадохме, попълнете останалите полета (име, заглавие и път), както е необходимо.


След това щракнете Запазете и конфигурирайте(Продължете и редактирайте)Настройте изгледа както обикновено. В критериите за филтриране добавих показване само на публикувани материали и желания тип възел и конфигурирах показването на необходимите полета (трябва да добавите тези полета към индекса, за да можете да филтрирате по тях).

На този етап сме готови с настройката на изгледа, сега нека преминем директно към филтъра за аспекти.

A/search_api_ranges.module +++ b/search_api_ranges.module @@ -144.11 +144.8 @@ функция search_api_ranges_minmax($variables, $order = "ASC") ( // в противен случай нашият min/max винаги ще бъде равен на въведеното от потребителя. $filters = &$query->getFilter()->getFilters(); foreach ($filters as $key => $filter) ( - - // Проверка за масив: филтрите в стар стил са обекти, които можем да пропуснем. - if (is_array) ($filter)) ( - if ($filter == $variables["range_field"] || ($filter != $variables["range_field"] && $filter == "")) ( - $ current_filter = $filters [$key]; + if(isset($filter->tags) && is_array($filter->tags))( + if(in_array("facet:".$variables["range_field"], $ filter->tags ))( unset($filters[$key]); ) )

Корекция на JQuery UI Slider: настройка на пренасочване

Във версия 7x-1.5 на модула се сблъсках с факта, че ако джаджата на плъзгача се намираше на страница, различна от страницата за търсене, тогава след промяна на ценовия диапазон посоката беше пренасочена към текущата страница, а не към страницата за търсене страница.
Грешката е във функцията search_api_ranges_block_slider_view_form_submit()(файл search_api_ranges.module, ред 364).
Наистина не разгледах какво има там и защо, просто промених малко кода на ред 427:

Drupal_goto($path, array("query" => array($params), "language" => $language)); + drupal_goto($values["path"], array("query" => array($params), "language" => $language));

след което проблемът беше решен.

Фасетираната навигация е проблем за всички сайтове за електронна търговия. Прекалено големият брой страници, които се използват за различни вариации на един и същи елемент, представлява заплаха за ефективността на търсенето. Това може да повлияе негативно върху SEO и потребителското изживяване. Експерти от блога SEO Hacker обясниха какво представлява фасетната навигация и как да я подобрим.

Фасетна навигация: Определение

Този тип навигация обикновено се намира в страничните ленти на сайтовете за електронна търговия и съдържа филтри и аспекти - параметри, които потребителят конфигурира по желание. позволява на клиентите на онлайн магазина да търсят продукта, който искат, като използват комбинация от атрибути, които ще филтрират продуктите, докато потребителите намерят това, от което се нуждаят.

Фасетите и филтрите са различни един от друг. Ето разликата:

  • Фасетите са индексирани категории. Те помагат за прецизиране на продуктовите списъци и действат като разширения на основните категории. Фасетите добавят уникално значение към всеки избор, който потребителят прави. Тъй като фасетите са индексирани, те трябва да изпращат подходящи сигнали до търсачката, като гарантират, че страницата съдържа всички важни атрибути.

  • Филтрите се използват за сортиране и прецизиране на елементи в списъците. Те са необходими за потребителите, но не и за търсачки. Филтрите не се индексират, защото не променят съдържанието на страницата, а само я сортират в различен ред. Това води до множество URL адреси с дублирано съдържание.

Потенциални проблеми

Всяка възможна комбинация от аспекти има свой собствен уникален URL адрес. Това може да причини някои проблеми от гледна точка на SEO. Ето основните от тях:

  • Дублирано съдържание.
  • Загуба на бюджет за сканиране.
  • Премахнете разликите във връзката.

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

Вероятността от канибализация на ключови думи също се увеличава. Няколко страници се опитват да се класират за едни и същи ключови думи, което води до по-малко последователни и по-ниски класации. Този проблем може да бъде избегнат, ако всяка ключова дума е насочена само към една страница.

Фасетирани решения за навигация

Когато избирате решение за фасетна навигация, помислете за крайната си цел: увеличаване на броя на страниците, които индексирате, или намаляване на броя на страниците, които не искате да индексирате. Ето някои решения, които могат да бъдат полезни за вас:

AJAX

Ако използвате AJAX, нов URL адрес не се създава, когато потребителят кликне върху аспект или филтър. Тъй като няма да има уникални URL адреси за всяка възможна комбинация от аспекти, проблемът с дублираното съдържание, канибализацията на ключови думи и напразните разходи за индексиране е потенциално елиминиран.

AJAX може да бъде ефективен само преди стартирането на сайта за електронна търговия. Не се използва за решаване на проблеми на съществуващи ресурси. Този метод също изисква определени разходи от ваша страна.

noindex таг

Тагът noindex се използва за изключване на ботове конкретна страницаот индекса. По този начин няма да се покаже в резултатите. Търсене в Google. Това помага за намаляване на количеството дублирано съдържание, което се появява в индекса и резултатите от търсенето.

Това няма да реши проблема с бюджета за обхождане, защото ботовете все още ще посещават страницата ви. Освен това не помага за разпределянето на стойността на връзките.

Атрибутът rel=canonical

С този атрибут казвате на Google, че имате една основна предпочитана страница за индексиране и класиране, а всички останали версии на съдържанието от тази страница са просто дубликати, които не е необходимо да бъдат индексирани.

София Ибрагимова

Маркетинг на съдържание

Ако една и съща страница на вашия сайт може да бъде достигната от множество URL адреси, роботите за търсене ще третират всеки URL като отделна страница. Ботовете ще решат, че съдържанието на вашия сайт не е уникално и това ще се отрази негативно на класирането и ще намали позицията ви в резултатите от търсенето. За да избегнете това, укажете главната канонична страница, като вмъкнете следната последователност от знаци в блока HEAD:

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

Robots.txt

Затварянето на някои страници от индексиране ви позволява да постигнете добри резултати. Това е просто, бързо и надежден начин. Най-лесният начин да направите това е да зададете персонализирана опция, за да посочите всички възможни комбинации от аспекти и филтри, които искате да блокирате. Включете го в края на всеки URL адрес, който искате да скриете (http://адрес на цялата страница/robots.txt) или използвайте мета маркера Robots в областта HEAD на кода на страницата.

Когато правите промени в URL адреса, имайте предвид, че са необходими 3-4 седмици на роботите да забележат и да отговорят на тези промени.

Също така има определени проблеми. Стойността на връзките ще бъде ограничена и блокиран URL може да бъде индексиран поради наличието на външни връзки.

Google Search Console

Това е чудесен начин временно да коригирате проблемите си, докато работите върху създаването на все по-добро и по-добро удобна системанавигация. Можете да използвате конзолата за търсене на Google, за да кажете на търсачката как да обхожда вашия сайт.

  • Впиши се сметкаконзола и изберете секцията „Обхождане“:

  • Кликнете върху бутона „URL параметри“:

  • Посочете въздействието, което всяка ваша настройка ще има върху страницата и как искате Google да третира тези страници.

Не забравяйте, че този метод скрива само дублирано съдържание от търсачките. Google роботи. Страниците все още ще се показват в Bing и Yahoo.

Как да подобрим фасетната навигация

Нека разгледаме накратко всички методи, които ви позволяват да създадете правилната фасетирана навигация:

  • Използване на AJAX
  • Премахнете или скрийте връзки към категории или филтрирайте страници, на които липсва съдържание.
  • Разрешаване на индексиране на определени комбинации от аспекти, които имат голям обем трафик от търсене
  • Създаване на йерархия на сайта чрез навигационни трохи в категории и подкатегории.
  • Създаване на канонични (основни) страници за дублирано съдържание.
  • Консолидирайте свойствата за индексиране от компонентни страници в цялата серия, като използвате маркиране на страница с rel="next" и rel="prev" .

Заключение

Всяко от споменатите решения има своите предимства и недостатъци. Няма универсално решение, всичко зависи от спецификата на вашия бизнес и конкретния случай. Оптимизираната фасетна навигация ще позволи на вашия сайт да насочва към по-широк набор от ключови думи. За да избегнете риск, уверете се, че навигацията не само отговаря на изискванията на роботите за търсене, но и осигурява добро потребителско изживяване.



Свързани публикации