26

I am planning on setting up a filter system (refine your search) in my ecommerce stores. You can see an example here: http://www.bettymills.com/shop/product/find/Air+and+HVAC+Filters

Platforms such as PrestaShop, OpenCart and Magento have what's called a Layered Navigation.

My question is what is the difference between the Layered Navigation in platforms such as Magento or PrestaShop in comparison to using something like Solr or Lucene for faceted navigation.

Can a similar result be accomplished via just php and mysql?

A detailed explanation is much appreciated.

Ravi Gupta
  • 6,258
  • 17
  • 56
  • 79
Adil
  • 3,183
  • 5
  • 28
  • 30

4 Answers4

52

Layered Navigation == Faceted Search.

They are the same thing, but Magento and al uses different wording, probably to be catchy. As far as I know, Magento supports both the Solr faceted search or the MySQL one. The main difference is the performance.

Performance is the main trade-off.

To do faceted search in MySQL requires you to join tables, while Solr indexes the document facets automatically for filtering. You can generally achieve fast response times using Solr (<100ms for a multi-facet search query) on average hardware. While MySQL will take longer for the same search, it can be optimized with indexes to achieve similar response times.

The downside to Solr is that it requires you to configure, secure and run yet another service on your server. It can also be pretty CPU and memory intensive depending on your configuration (Tomcat, jetty, etc.).

Faceted search in PHP/MySQL is possible, and not as hard as you'd think.

You need a specific database schema, but it's feasible. Here's a simple example:

product

+----+------------+
| id | name       |
+----+------------+
|  1 | blue paint |
|  2 | red paint  |
+----+------------+

classification

+----+----------+
| id | name     |
+----+----------+
|  1 | color    |
|  2 | material |
|  3 | dept     |
+----+----------+

product_classification

+------------+-------------------+-------+
| product_id | classification_id | value |
+------------+-------------------+-------+
|          1 |                 1 | blue  |
|          1 |                 2 | latex |
|          1 |                 3 | paint |
|          1 |                 3 | home  |
|          2 |                 1 | red   |
|          2 |                 2 | latex |
|          2 |                 3 | paint |
|          2 |                 3 | home  |
+------------+-------------------+-------+

So, say someones search for paint, you'd do something like:

SELECT p.* FROM product p WHERE name LIKE '%paint%';

This would return both entries from the product table.

Once your search has executed, you can fetch the associated facets (filters) of your result using a query like this one:

SELECT c.id, c.name, pc.value FROM product p
   LEFT JOIN product_classification pc ON pc.product_id = p.id
   LEFT JOIN classification c ON c.id = pc.classification_id
WHERE p.name LIKE '%paint%'
GROUP BY c.id, pc.value
ORDER BY c.id;

This'll give you something like:

+------+----------+-------+
| id   | name     | value |
+------+----------+-------+
|    1 | color    | blue  |
|    1 | color    | red   |
|    2 | material | latex |
|    3 | dept     | home  |
|    3 | dept     | paint |
+------+----------+-------+

So, in your result set, you know that there are products whose color are blue and red, that the only material it's made from is latex, and that it can be found in departments home and paint.

Once a user select a facet, just modify the original search query:

SELECT p.* FROM product p
   LEFT JOIN product_classification pc ON pc.product_id = p.id
WHERE 
   p.name LIKE '%paint%' AND (
      (pc.classification_id = 1 AND pc.value = 'blue') OR
      (pc.classification_id = 3 AND pc.value = 'home')
   )
GROUP BY p.id
HAVING COUNT(p.id) = 2;

So, here the user is searching for keyword paint, and includes two facets: facet blue for color, and home for department. This'll give you:

+----+------------+
| id | name       |
+----+------------+
|  1 | blue paint |
+----+------------+

So, in conclusion. Although it's available out-of-the-box in Solr, it's possible to implement it in SQL fairly easily.

netcoder
  • 66,435
  • 19
  • 125
  • 142
  • What would be optimal way to structure this in the nested and statement with multiple facets? Should every facet be followed by an OR? – Ryan Jun 29 '12 at 13:25
  • 5
    @RPM: Yes. Because you want MySQL to match one facet or the other, then check if all facets were matched using the `HAVING` clause (you can't tell MySQL to match two facets using `AND` because it's impossible for it because of its relational nature, e.g.: `value` can't be `blue` AND `red` at the same time). So, if you have 4 facets, you need three conditions with `OR` clauses, and an `HAVING COUNT()` of `4`. – netcoder Jun 29 '12 at 13:49
  • I just noticed the corrleation between the `HAVING COUNT()` and the number of facets currently. So if you had a 3rd facet in that query It would be OR clause? What is the pattern? Do all the facets go inside the nested AND? – Ryan Jun 29 '12 at 13:51
  • 2
    @RPM: Yes, all facets go in the nested `AND`. The pattern is the following. When using `OR` clauses, MySQL will return one or multiple rows, with identical `p.id` (item), for each facet that matched. So, if you an item (`p.id = 1`) that matches `blue` and `paint` you will have two rows: `p.id=1, value=blue` and `p.id=1, value=paint`. The `HAVING` clause makes sure that you indeed have two rows, one for each facet selected. Remove the `GROUP BY` clause and you'll see what I mean. – netcoder Jun 29 '12 at 13:57
  • This all makes sense now. I was over thinking the concept way to much. Thank you for responding to this comment by the way. You really helped me visualize this. When a user has selected a facet, do you think a `CASE` statement to determine the facets that do not exist for the given set would be appropriate, and allow all the facets to still be shown but not selectable until a facet is revised the case would determine if it should have a `NULL` or `0` – Ryan Jun 29 '12 at 14:10
  • 1
    @RPM: Not entirely sure what you mean. You may want to open a question and link to this one, it'll be easier to explain for you and easier to answer for me and other users. It's a little hard to explain complicated SQL queries in comments. ;-) – netcoder Jun 29 '12 at 14:46
  • Can this same behavior be achieved with Sphinx? – hakazvaka Jun 18 '13 at 13:19
  • 1
    The last query can be also `SELECT p.* FROM product p LEFT JOIN product_classification pc1 ON pc1.product_id = p.id LEFT JOIN product_classification pc2 ON pc2.product_id = p.id WHERE p.name LIKE '%paint%' AND pc1.classification_id = 1 AND pc1.value = 'blue' pc2.classification_id = 3 AND pc2.value = 'home'` – Eduardo Aug 25 '13 at 02:08
  • How would one go about if he wanted to show the itemcount for each facet? I've tried a couple of things but can't seem to get it to work using the method described here. – Owen Jan 27 '14 at 18:19
  • Wow, this was truly helpful. But I have one problem. How can I join another table properly? I'd like to join reviews for having a review_count on my products for sorting, but if I do that, the sql code breaks and something totally different is returned... – Luuk Van Dongen Feb 01 '15 at 02:54
1

out of the solr box, you can use calculated facet, range, choose a facet or exclude one, declare if a facet is mono valued, or multi valued with a very low cpu/ram cost

On the other hand, it takes some time to parameter and secure the solr installation, it also takes some time to crawl your data.

flo850
  • 138
  • 1
  • 4
1

Magento Enterprise Edition has an implementation of Solr with faceted search. Still you need to configure Solr to index the correct data; i.e. Solr runs on Java on a host with a specific port. Magento connects to it through a given url. When Magento sets up the faceted search, it does a request to Solr and processes the received xml into a form on the frontend. The difference would be one of speed. Requesting to Solr is very fast. If you have about 100,000+ products in your shop and want quick responses on search requests, you can use Solr. But still, if you have a separate server for the Magento database with a lot of memory, you can also just use Magento's built in Mysql based faceted search. If you don't have money to spend on Magento EE, you can use this solr implementation. But I do not have any experience with this one.

y_a_v_a
  • 122
  • 1
  • 4
0

You can created faceted search with just PHP and MySQL, Drupal Faceted Search is a good example. But if you already use Solr, you get faceted search included for free.

Karl-Bjørnar Øie
  • 5,554
  • 1
  • 24
  • 30