Finding the right path: how faceted navigation affects SEO (translation). Faceted Search module - search using "clarifications"


We have released a new book “Content Marketing in in social networks: How to get into your subscribers’ heads and make them fall in love with your brand.”

Subscribe

Faceted navigation is a problem for all e-commerce sites. Excessive number of pages that are used for different options of the same element poses a threat to search efficiency. This can negatively impact SEO and user experience. Experts from the SEO Hacker blog explained what faceted navigation is and how to improve it.

Faceted Navigation: Definition

This type of navigation is usually found in the sidebars of websites. ecommerce, contains filters and facets - parameters that the user configures as desired. allows online store customers to search for the product they want using a combination of attributes that will filter products until users find what they need.

Facets and filters are different from each other. Here's the difference:

  • Facets are indexed categories. They help refine product listings and act as extensions of core categories. Facets add unique meaning to each choice the user makes. Since facets are indexed, they must send relevant signals to the search engine, ensuring that the page contains all the important attributes.

  • Filters are used to sort and refine items within lists. They are necessary for users, but not for search engines. Filters are not indexed because they do not change the content of the page, but only sort it in a different order. This results in multiple URLs having duplicate content.

Potential problems

Each possible facet combination has its own unique URL. It may cause some problems in terms of SEO perspective. Here are the main ones:

  • Duplicate content.
  • Waste of budget on scanning.
  • Eliminate link differences.

As your site grows, so does the number of duplicate pages. Incoming links may go to various duplicate pages. This reduces the value of links and limits the ability of pages to rank.

The likelihood of keyword cannibalization also increases. Multiple pages try to rank for the same keywords, resulting in less consistent and lower rankings. This problem could have been avoided if every keyword was intended for a single page only.

Faceted Navigation Solutions

When choosing a solution for faceted navigation, consider your end goal: increasing the number of pages you index or reducing the number of pages you don't want indexed. Here are some solutions that may be useful for you:

AJAX

If you use AJAX, a new URL is not created when the user clicks on a facet or filter. Since there will be no unique URLs for every possible facet combination, the problem of duplicate content, keyword cannibalization, and wasted indexing costs is potentially eliminated.

AJAX can only be effective before the e-commerce site is launched. It is not used to solve problems of existing resources. This method also requires certain expenses on your part.

noindex tag

The noindex tag is used to tell bots to exclude a specific page from the index. This way it won't show up in the results. Google search. This helps reduce the amount of duplicate content that appears in the index and search results.

This won't solve the crawl budget problem because bots will still visit your page. It also doesn't help distribute the value of the links.

The rel=canonical attribute

With this attribute, you tell Google that you have one main preferred page to index and rank, and all other versions of content from that page are just duplicates that don't need to be indexed.

Sofia Ibragimova

Content Marketer

If the same page on your site can be reached from multiple URLs, search robots will treat each URL as a separate page. Bots will decide that the content on your site is not unique, and this will negatively affect rankings and reduce your position in search results. To avoid this, specify the main canonical page by inserting the following sequence of characters into the HEAD block:

You can use canonical pages to solve the problem of duplicate content, and the share link will be merged with your main page. But there is a chance that bots will still crawl duplicate pages, which is a waste of crawling budget.

Robots.txt

Blocking some pages from indexing allows you to achieve good results. It's simple, fast and reliable way. It is most convenient to set a custom parameter to specify all possible combinations facets and filters that you want to block. Include it at the end of each URL you want to hide (http://full page address/robots.txt) or use the Robots meta tag in the HEAD area of ​​the page code.

When making changes to the URL, keep in mind that it takes 3-4 weeks for robots to notice and respond to these changes.

There are certain problems here too. The value of links will be limited, and a blocked URL may be indexed due to the presence of external links.

Google Search Console

This great way temporarily fix your problems while you work on creating a more advanced and user-friendly navigation system. you can use Google console Search to tell the search engine how to crawl your site.

  • Sign in account console and select the “Crawl” section:

  • Indicate the impact each of your settings will have on the page and how you want Google to treat those pages.

Remember that this method only hides duplicate content from search engines. Google robots. Pages will still appear in Bing and Yahoo.

How to Improve Faceted Navigation

Let's briefly consider all the methods that allow you to create the correct faceted navigation:

  • Using AJAX
  • Remove or hide links to categories or filter pages that are missing content.
  • Indexing permission certain combinations facets that have a high volume of search traffic
  • Setting up a site hierarchy via bread crumbs in categories and subcategories.
  • Creating canonical (main) pages for duplicate content.
  • Consolidate indexing properties from component pages across the entire series using page markup with rel="next" and rel="prev" .

Conclusion

Each of the solutions mentioned has its own advantages and disadvantages. Universal solution does not exist, it all depends on the specifics of your business and the specific case. Optimized faceted navigation will allow your site to target a wider range of keywords. To avoid risk, make sure that the navigation not only meets the requirements of search robots, but also provides a good user experience.

We took a quick look at the installation and basic syntax of PINQ, which has been ported to PHP version LINQ. In this article, we'll look at how to use PINQ to simulate the faceted search feature in MySQL.

In this article we will not cover all aspects of faceted search. Interested people can search for suitable information on the Internet.

A typical faceted search works like this:

  • The user enters a keyword, or several keywords, to search. For example, “router” to search for products in which the word “router” appears in the description, keywords, category name, tags, etc.
  • The site returns a list of products that match these criteria.
  • The site provides several links to customize your search terms. For example, it may allow you to specify specific manufacturers routers, or set a price range, or other features.
  • The user can continue to specify additional search criteria in order to obtain the data set of interest.

Faceted search is very popular and is powerful tool, it can be observed on almost any e-commerce related website.

Unfortunately, faceted search is not built into MySQL. So what should we do if we still use MySQL, but want to give the user this opportunity?

With PINQ, which has a similar, powerful and simple approach, we can achieve the same behavior as if we were using other database engines.

Expanding the demo from the first part

Comment: All code from this part, and from the first part, can be found in the repository.

In this article, we'll expand on the demo from Part 1 with a significant improvement in the form of facet search.

Let's start with index.php by adding following lines:

$app->get("demo2", function () use ($app) ( global $demo; $test2 = new pinqDemo\Demo($app); return $test2->test2($app, $demo->test1 ($app)); )); $app->get("demo2/facet/(key)/(value)", function ($key, $value) use ($app) ( global $demo; $test3 = new pinqDemo\Demo($app); return $test3->test3($app, $demo->test1($app), $key, $value); ));

The first route takes us to a page to view all posts that match the keyword search. To keep the example simple, we select all books from the book_book table. It will also display the resulting data set and a set of links to specify the search criteria.

IN real applications, after clicking on such links, all facet filters will adjust to the boundary values ​​of the resulting data set. The user will thus be able to sequentially add new search conditions, for example, first select a manufacturer, then specify a price range, etc.

But in this example we will not implement this behavior - all filters will reflect the boundary values ​​​​of the original data set. This is the first limitation and the first candidate for improvement in our demo.

As you can see in the code above, the actual functions are located in another file called pinqDemo.php. Let's take a look at the corresponding code that provides the faceted search feature.

Aspect class

The first step is to create a class that represents an aspect. In general, an aspect should contain several properties:

  • The data it operates on ( $data)
  • The key by which the grouping is performed ( $key)
  • Key type ($type). Can be one of the following:
    • specify the full string for an exact match
    • indicate part of the string (usually the initial one) to search by pattern
    • indicate a range of values, for grouping by range
  • if the key type is a range of values, you need to define a value step to determine the lower and upper bounds of the range; or if the type is part of a string, you must specify how many first letters will be used for grouping ($range)

Grouping- the most critical part of the aspect. All aggregated information that an aspect may be able to return depends on the grouping criteria. Typically the most used search criteria are “Full String”, “Part of String”, or “Range of Values”.

Namespace classFacet ( use Pinq\ITraversable, Pinq\Traversable; class Facet ( public $data; // Original data set public $key; // field by which to group public $type; // F: entire row; S: start strings; R: range; public $range; // only plays a role if $type != F ... public function getFacet() ( $filter = ""; if ($this->type == "F") // entire line ( ... ) elseif ($this->type == "S") // start of line ( ... ) elseif ($this->type == "R") // range of values ​​( $ 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 $filter; ) ) )

The main function of this class is to return a filtered dataset based on the original dataset and aspect properties. From the code it is clear that for various types accounts are used various ways grouping data. In the code above we showed what the code might look like if we group the data by a range of values ​​in increments specified in $range.

Setting aspects and displaying source data

Public function test2($app, $data) ( $facet = $this->getFacet($data); return $app["twig"]->render("demo2.html.twig", array("facet" = > $facet, "data" => $data)); ) private function getFacet($originalData) ( $facet = array(); $data = \Pinq\Traversable::from($originalData); // 3 creation examples various objects aspects, and return aspects $filter1 = new \classFacet\Facet($data, "author", "F"); $filter2 = new \classFacet\Facet($data, "title", "S", 6); $filter3 = new \classFacet\Facet($data, "price", "R", 10); $facet[$filter1->key] = $filter1->getFacet(); $facet[$filter2->key] = $filter2->getFacet(); $facet[$filter3->key] = $filter3->getFacet(); return $facet; )

In the getFacet() method we do the following:

  • Convert the original data into a Pinq\Traversable object for further processing
  • We create three aspects. The 'author' aspect will group by the author field, and implement grouping by the entire row; aspect 'title' - by the title field with grouping by part of the line (by the first 6 characters); aspect 'price' - by the price field with grouping by range (in increments of 10)
  • Finally, we extract the aspects and return them to the test2 function so that they can be output to the template for display

Outputting aspects and filtered data

In most cases, filters will be displayed as a line, and will lead you to view the filtered result.

We've already created a route ("demo2/facet/(key)/(value)") to display faceted search results and filter links.

The route takes two parameters, depending on the key being filtered by and the value for that key. The test3 function that is bound to this route is shown below:

Public function 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)); )

Basically, depending on the key, we apply filtering (an anonymous function in the where statement) according to the passed value and get the following set of filtered data. We can also set the order of data filtering.

Finally, we display the raw data (along with filters) in the template. This route uses the same pattern we used in "demo2".

Search Bar

    (% for k, v in facet %)
  • ((k|capitalize))
    • (% for vv in v %)
    • ((vv.count))((vv.key))
    • (%endfor%)
    (%endfor%)

We need to remember that the aspects generated by our application are nested arrays. At the first level, this is an array of all aspects, and, in our case, there are three of them (for author, title, price, respectively).

Each aspect has a key-value array, so we can iterate over it using normal methods.

Notice how we build the URLs for our links. We use both the outer loop key (k) and the inner loop keys (vv.key) as parameters for the route ("demo2/facet/(key)/(value)"). The size of the arrays (vv.count) is used for display in the template.

The first image shows the original data set, and the second image is filtered by price range from $0 to $10, and sorted by author.

Great, we were able to simulate faceted search in our application!

Before concluding this article, we need to take a final look at our example and determine what can be improved and what limitations we have.

Possible improvements

In general, this is a very basic example. We've just gone over the basic syntax and concepts and implemented them as a working example. As previously stated, we have several areas that could be improved for greater flexibility.

We need to implement “overlay” search criteria, since the current example limits us to the ability to apply search filtering only to the original data set; we cannot apply faceted search to an already filtered result. This is the biggest improvement I can imagine.

Restrictions

The facet search implemented in this article has serious limitations (which may also apply to other facet search implementations):

We fetch data from MySQL every time

This application uses the Silex framework. Like any single entry point framework like Silex, Symfony, Laravel, its index.php (or app.php) file is called every time a route is parsed and controller functions are executed.

If you look at the code in our index.php, you will notice that the following line of code:

$demo = new pinqDemo\Demo($app);

is called every time the application page is rendered, which means the following lines of code are executed each time:

Class Demo ( private $books = ""; public function __construct($app) ( $sql = "select * from book_book order by id"; $this->books = $app["db"]->fetchAll($sql ); )

Will it be better if we don't use a framework? Well, despite the fact that developing applications without frameworks is not a good idea, I can say that we will encounter the same problems: data (and state) are not saved between different HTTP requests. This is a fundamental characteristic of HTTP. This can be avoided by using caching mechanisms.

We saved some SQL queries using aspects. Instead of passing one select query to retrieve the data, and three group by queries with corresponding where clauses, we ran just one where query, and used PINQ to get the aggregated information.

Conclusion

In this part, we implemented the ability to facet search a collection of books. As I said, this is just a small example, which has room for improvement, and which has a number of limitations.

Faceted navigation - this is a type of site structuring in which users have the opportunity to specify different facets (desired parameters) in order to find the product or service they are looking for.

This allows online store visitors to easily navigate through the variety of products or services offered, quickly arriving at what they are looking for. Only in this case, each user searches along his own path.

The best way to demonstrate the principle of faceted navigation is with a specific example.

For example, you are going to buy mobile phone in the online store. Do you want to find a phone number? a certain model, colors, prices, brands. It would be easier and faster to find what you need by narrowing your search using several or all parameters (facets).

Such flexibility of the site structure allows you to easily create landing pages for individual keywords. This may seem simple enough on paper. In practice, everything is much more complicated.

Let's consider the main difficult questions.

1. How many facets are needed for your site to be indexed well?

Ideally, the “depth” of a facet should not exceed 100 items. This will allow search robots to index all pages of the resource. Most website promotion specialists tend to believe that search robots can recognize more than 100 links on one page.

It is best to adhere to the following opinion: Since most sites have navigation links on every page anyway, the number of product links per separate page should not exceed 100.

2. Facets and search filters

There may be options on your site that you want to offer to visitors, but that are not that important from a search engine optimization perspective. For example, it is very convenient for visitors to select products by the right size, and you may not actually be interested in indexing this particular resource page. In this case, use filters using Java Script and block certain internal pages from indexing.

3. Sorting

You might want to include Extra options choice (for example, the price of a product, its popularity, etc.). Of course, this is very convenient for customers, but there is a risk of duplicate content. If you don't want the same page to be indexed search robot several times due to the presence of different navigation paths to find it, use JavaScript or Ajax.

4. The problem of duplicate content

With a faceted site structure, the problem of duplicate content arises due to the presence of different navigation paths to the same page. And if you are not careful about this issue, you will end up with the same content on several pages.

The navigation path that a visitor uses to find a specific product is not important. It is important that only one of the paths is indexed. To do this, use a CMS. Otherwise, the same page will be indexed more than once.

And once again about the uniqueness of the content...

Let's say you've created a reasonable faceted navigation, relevant pages for every keyword or phrase, but despite all this, your site still contains a lot similar friends on other pages, the information content of which is product lists. Therefore, each page must have its own unique content, and what page is more important, the higher the uniqueness index its content should be.

So here's what to remember:

  1. create as many facets as necessary to place no more than 100 products on one page;
  2. make sure that for each key phrase, by which you want to rank in search engines, there is its own landing page;
  3. incorrect sorting can lead to duplicate content, to avoid this use Ajax and Java Script to close some internal pages from indexing;
  4. no matter which navigation path the user uses to find a particular page, only one page should be indexed;
  5. Do not forget: content should be more interesting and attractive.

Organizes the so-called faceted search (faceted navigation) on the site. Its meaning is that search results can be refined using various characteristics material - author, type, term, date of creation, etc.

For example, if you have an online store selling electronic technology, and the user enters the phrase into the search audio player. On the results page, in addition to the results themselves, there will be facets:

- Chapter: audio equipment (54), computer technology (85)
- Brand: Apple (25), Samsung (68), iRiver (78)
- Availability in stock: yes (456), no (12)
- Price: 100-1000$ (45), 1000-10000$ (12)

etc. The number of products (nodes) that meet these characteristics will be indicated in brackets. By clicking on the links, the user will narrow the search results.


On the one hand, this is an alternative to expanded filters in Views, on the other, an alternative to the standard advanced search.

Installation

Facets section

In this section, you can specify which facets to use when searching. For example, allow you to select materials by taxonomy, date added, or author. The number of facets depends on the included modules.

Results page section

Display style- search results display style: Extracts means to display as in a normal search (highlighted text, author, date); Teasers means displaying teasers of materials using the appropriate node.tpl.php.

Use the Extracts display style selectively- If the option is checked, then the style Extracts will always be applied if a keyword is entered. If you do not check this option, you can use the module as a replacement for navigating taxonomy terms.

Current search section

Allows you to turn on the block Current search , which displays the search terms:

Contents of articles:
Previous article:

Facets are defined constraints on the XDTO value type. One facet defines the constraint type and the constraint value. For example [Maximum inclusive - 5]. The XDTO value type can store several facets, but their types must be unique, that is, you cannot specify two facets [Maximum inclusive - 5] and [Maximum inclusive - 3].

In this article I want to show how you can use facets to check inputs and how to make a ws-operation parameter of a composite type.

Let's put simple task- upload items via a web service. We will upload the code, name, price and balance in the store. But the directory can be very large, so when calling the ws operation it should be possible to set the selection. We will select by item code.

Let's create new base and add new package XDTO, let's call it PackageXDTO, indicate the namespace.

Next, add a Value Type to the package as shown in the figure.


Let's create a "Code" type to organize selection by a unique item identifier. Respectively, new type The "code" can be derived from the string type by adding a character limit. There should be 9 characters, that is, the number of characters in the nomenclature code. For the "Space characters" facet, set the value to "collapse", this will display an error if there are spaces in the code.


Now let’s create the “Price” Value Type in the same way. For it we will set the minimum to 0, maximum to 1,000,000.


To solve the problem, we will create a reference book of nomenclature; we will store the remainder in one of its details - this is not important.


Well, now let's start creating a web service. Let's call it "Remains" and add 3 parameters:
  • Code is the Code type that we previously created. By this parameter We will establish selection based on item code;
  • PriceFrom - type Price. This is the lower limit of the price of a product;
  • PriceBefore - type Price. This is the upper limit of the price of a product.

In order for the web service to display an array of products, each of which has a code, name, price and balance, let’s create an XDTO “Nomenclature” Object in which we specify the fields:

  • Code - type Code;
  • Name - string type;
  • Price - type Price;
  • Remainder - type int

And let's create an XDTO Object "Products", which will have one property "Nomenclature", but with the ability to display it as a list. For the type of the "Item" field of the "Products" object, specify the "Nomenclature" object. You can read more about how to pass an array through a web service.

Let's move on to the properties of the "Remains" operation. Let's specify the return value type - "Products" and open its module. Let's write the following code:

Function Remains (Code, PriceFrom, PriceTo)

Request = New Request;
Request . Text =
"CHOOSE
|Nomenclature.Code,
|Nomenclature.Name,
|Nomenclature.Price,
|Nomenclature.Remainder
|FROM
|Directory.Nomenclature AS Nomenclature
|WHERE
|1 = 1
|And 2 = 2" ;

IfValueFilled(Code )
AND Code<>"000000000" Then
Request . Text = StrReplace(Query . Text , " 1 = 1 " , " Nomenclature.Code = &Code" );
Request . SetParameter("Code", Code);
endIf;

If not PriceFrom = PriceToThen
Request . Text = StrReplace (Query . Text , "2 = 2" , "Nomenclature. Price BETWEEN &PriceFrom AND &PriceTo");
Request . SetParameter("PriceDo", PriceDo);
Request . SetParameter("PriceFrom", PriceFrom);
endIf;

Query Result= Request. Run();

SelectionDetailedRecords= Query Result. Choose ();
TypeXDTOProducts = FactoryXDTO . Type(, "Products");

Products = FactoryXDTO . Create(TypeXDTOProducts);
TypeXDTONomenclature= FactoryXDTO . Type ( "http://codenotes-1c.blogspot.ru/", "Nomenclature" );
ByeSelectionDetailedRecords. Next() Loop
Item = FactoryXDTO . Create ( TypeXDTONomenclature);
Nomenclature. Code =SelectionDetailedRecords. Code ;
Nomenclature. Name =SelectionDetailedRecords. Name ;
Nomenclature. Price =SelectionDetailedRecords. Price ;
Nomenclature. Remainder =SelectionDetailedRecords. Remainder ;
Goods . Nomenclature. Add(Nomenclature);
EndCycle ;

Return Goods ;

EndFunction

To demonstrate the operation of facets, it is not necessary to look at the code itself; now it is important to check that without coding the restrictions on input parameters they are present due to the facets.
To do this, we call the ws operation with various parameters:

  • without parameters. To be precise, we will indicate the code "000000000", the price from =0, the price to = 0. Because empty parameters are unacceptable.

Well, we will indicate this type for the “Code” parameter of the ws-operation “Remains”. After which we will be able to indicate the item code both as a number and as a string. Without modifying the code, we can only specify 0, which corresponds to an empty parameter value, and the selection will not be installed.

And that's cool. After all, if we can make restrictions on input data in code, without using facets, then we cannot do this with a composite data type. This provides ample opportunities when developing web services.

Next, for reference, I will give the value of each property field. This description taken from the link: What does the concept of “Facet” refer to within the XDTO model? What is a facet? Many thanks to the authors!

  • Base type - a type that is used as a basis. Default is anyType. The allowed set of facets depends on this value.
  • Length - length facet. Contains the number of length units, with the length unit having different meanings for different types. For the "string" and "anyURI" types, the length contains the number of characters. For the "hexBinary" and "base64Binary" types, the length contains the number of bytes of binary data. For list-defined types, length contains the number of elements of the list;
  • MaxInclusive—The maximum facet that includes the boundary. Limits the value space of this type maximum value. Any value of this type is less than or equal to the specified value;
  • MaxLength—facet of maximum length. Contains maximum amount units of length, with the unit of length having different meanings for different types. For type "string" maximum length contains the maximum number of characters. For the "hexBinary" and "base64Binary" types, the maximum length contains the maximum number of bytes of binary data. For list-defined types, the maximum length contains the maximum number of list elements;
  • MaxExclusive is a maximum facet that does not include a boundary. Limits the value space of a given type to its maximum value. Any value of this type is less than the specified value;
  • MinInclusive - facet of the minimum that includes the boundary. Limits the value space of a given type minimum value. Any value of this type is greater than or equal to the specified value;
  • MinLength—minimal length facet. Contains minimal amount units of length, with the unit of length having different meanings for different types. For the "string" type, the minimum length contains the minimum number of characters. For the "hexBinary" and "base64Binary" types, the minimum length contains the minimum number of bytes of binary data. For list-defined types, the minimum length contains the minimum number of list elements;
  • MinExclusive—a facet of a minimum that does not include a boundary. Limits the value space of a given type to a minimum value. Any value of this type is greater than the specified value;
  • Enumeration is an enumeration facet. Defines a set acceptable values of this type;
  • WhitespaceCharacters - facet whitespace characters. Can take one of three values:
    • Save - the string can contain any whitespace characters;
    • Replace - The line must not contain #x9 (tab), #xA (line feed) and #xD (carriage return). If they exist, they must be replaced with the #x20 (space) character;
    • Collapse—In addition to the requirements specified for the replace value, the string must not contain paired #x20 (space) characters or leading or trailing #x20 (space) characters;
  • DigitsTotal - facet of the total number of digits. Contains the total number of digits of a number (integer part plus fractional part);
  • FractionalPartDigits - facet of the number of digits of the fractional part. Contains the number of digits of the fractional part of the number.






2024 gtavrl.ru.