Post by bald » Sat Feb 26, 2011 7:06 am

OC v1.4.9.3
Hey, I've just been dealing with OC's Search engine way of work trying to customize it for my purposes and wanted to share my idea.

Basically speaking, Product Name and Model are essential elements of describing properties of my products. I needed to search those fields at once using multiple keywords randomly arranged, finding products containing all given keywords in Name and Model (optionally Description).
The reason I needed it to work this way was that the more keywords I used, the more results I got while using SQL's OR operator to combine Name and Model fields. I guess customers would (I would at last) use more keyword to narrow the search result.

Despite main changes being in the catalog/model/catalog/product.php file, I had to make some other minor changes in other files (eg. hiding "Search model/description" checkboxes, making it a default and only option). I'm at the testing stage right now, should you like me to contribute it as a mod, I'll try in spare time.

Last few words to explain what I wanted to achieve. Since Product Name, Model and Description are separate columns in separate tables, after trying Match() Against() (no luck), I thought it would be possible to search those three values at once by merging them together. Here comes SQL CONCAT function. A godsent, for me at last ;D

BTW, I use vQMod to modify OC files.

Open file: catalog/model/catalog/product.php, find (2 occurences, ~182 and 252 line, about 10-line block of code):

Code: Select all

			if (!$description) {
				$sql .= " AND (LCASE(pd.name) LIKE '%" . $this->db->escape(strtolower($keyword)) . "%'";
			} else {
				$sql .= " AND (LCASE(pd.name) LIKE '%" . $this->db->escape(strtolower($keyword)) . "%' OR LCASE(pd.description) LIKE '%" . $this->db->escape(strtolower($keyword)) . "%'";
			}
			
			if (!$model) {
				$sql .= ")";
			} else {
				$sql .= " OR LCASE(p.model) LIKE '%" . $this->db->escape(strtolower($keyword)) . "%')";
			}
and replace this block with:

Code: Select all

$keyword = preg_replace("/^[^a-z0-9]+|[^a-z0-9]+$/", "", mb_strtolower($keyword, "UTF-8")); //trim special chars from ends, diacritics-safe strtolower - you can add your language specific diacritics to preg patterns
$keywords = explode(" ", $keyword); //explode multiple keywords
foreach ($keywords as $keyword) {
	$sql .= " AND CONCAT(LCASE(pd.name), LCASE(pd.description), LCASE(p.model)) LIKE '%" . $this->db->escape(mb_strtolower($keyword, "UTF-8")) . "%'";
}
Remember, it's only for test purposes, to share idea. I haven't got it running on production cart yet, just localhost installation and still customizing.

How do you like it?


UPDATE:
For those of you who use vQMod and would like to try my modification I attach a vQMod file.

Changes it makes to storefront:
- disables "Advanced search" link,
- searches model and description by default,
- hides "Search model", "Search description" checkboxes.

Entering keywords followed by spaces seeks for all of them in Name, Model, Description altogether at once.
Entering quoted phrase seeks for it as an exact phrase in Name, Model, Description altogether at once.

Attachments

v1.1.0
OC v1.4.9.3

Last edited by bald on Sun Feb 27, 2011 9:19 pm, edited 2 times in total.

Diagonal. Tires for 2-wheelers.
http://www.diagonal-opony.pl
OC 1.4.9.4


User avatar
Newbie

Posts

Joined
Sat Feb 26, 2011 5:35 am
Location - Olsztyn, Poland

Post by bald » Sat Feb 26, 2011 7:37 pm

UPDATE

I found solution for parsing more complex search expressions. This is not my idea, I got the code from php.net preg_split function comments.

Find:

Code: Select all

				$keyword = htmlspecialchars_decode(mb_strtolower($keyword, "UTF-8"));
				if (preg_match("/^[\"].*[\"]$/", $keyword)) {
					$keyword = preg_replace("/^[\"]/", "", $keyword);
					$keyword = preg_replace("/[\"]$/", "", $keyword);
				}
				else {
					$keyword = preg_replace("/^[^a-z0-9]+|[^a-z0-9]+$/", "", $keyword);
					$keyword = preg_replace("/[^a-z0-9/", "%", $keyword);
				}
				$keywords = explode("%", $keyword);
Replace with:

Code: Select all

				$search_expression = htmlspecialchars_decode(mb_strtolower($keyword, "UTF-8"));
				$words = preg_split("/[\s,]*\\\"([^\\\"]+)\\\"[\s,]*|" . "[\s,]*'([^']+)'[\s,]*|" . "[\s,]+/", $search_expression, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
				$keywords = $words;

Updated vQMod xml file in the first post.
Last edited by bald on Wed Mar 02, 2011 2:27 am, edited 1 time in total.

Diagonal. Tires for 2-wheelers.
http://www.diagonal-opony.pl
OC 1.4.9.4


User avatar
Newbie

Posts

Joined
Sat Feb 26, 2011 5:35 am
Location - Olsztyn, Poland

Post by marc_cole » Sun Feb 27, 2011 12:14 am

Thanks for posting this. I was eager to try it out, but unfortunately, v1.1.0 doesn't work for me. Even after removing all my other vQmods, I get this error when doing a search:

Code: Select all

Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'AND CONCAT(LCASE(pd.name), LCASE(pd.description), LCASE(p.model)) LIKE '%s2442c%' at line 1
Error No: 1064
SELECT COUNT(*) AS total FROM product p LEFT JOIN product_description pd ON (p.product_id = pd.product_id AND pd.language_id = '1') LEFT JOIN product_to_store p2s ON (p.product_id = p2s.product_id AND p2s.store_id = '0') WHERE AND CONCAT(LCASE(pd.name), LCASE(pd.description), LCASE(p.model)) LIKE '%s2442c%' AND p.status = '1' AND p.date_available <= NOW()
BTW, I figured I'd mention that when you update a file, standard practice is to post the update message like you did, but put the updated file in the first post—not in subsequent posts. That way, if there are multiple updates in the file's life, or if this thread gets exceedingly long ;) , it makes it easy to always find the latest update in the first post.

Thanks again,
Marc

OpenCart v1.4.9.4
VQMod | Categories Home | Cleaner By Default - 2 Column | Speak Good English


Active Member

Posts

Joined
Tue Dec 14, 2010 11:26 am
Location - Seattle, WA

Post by bald » Sun Feb 27, 2011 3:47 am

Ohkay, it's been a party evening tonight, but I see that there's kind of difference in our product.php files.
Could you check your catalog/model/catalog/product.php file, at line 180.

The mod works fine with and without any other xml vQmods on my local installation.
There's my product.php, lines 178-192:

Code: Select all

		if ($keyword) {
						
			$sql = "SELECT *, pd.name AS name, p.image, m.name AS manufacturer, ss.name AS stock, (SELECT AVG(r.rating) FROM " . DB_PREFIX . "review r WHERE p.product_id = r.product_id GROUP BY r.product_id) AS rating FROM " . DB_PREFIX . "product p LEFT JOIN " . DB_PREFIX . "product_description pd ON (p.product_id = pd.product_id) LEFT JOIN " . DB_PREFIX . "product_to_store p2s ON (p.product_id = p2s.product_id) LEFT JOIN " . DB_PREFIX . "manufacturer m ON (p.manufacturer_id = m.manufacturer_id) LEFT JOIN " . DB_PREFIX . "stock_status ss ON (p.stock_status_id = ss.stock_status_id) WHERE pd.language_id = '" . (int)$this->config->get('config_language_id') . "' AND p2s.store_id = '" . (int)$this->config->get('config_store_id') . "' AND ss.language_id = '" . (int)$this->config->get('config_language_id') . "'";
			
			if (!$description) {
				$sql .= " AND (LCASE(pd.name) LIKE '%" . $this->db->escape(strtolower($keyword)) . "%'";
			} else {
				$sql .= " AND (LCASE(pd.name) LIKE '%" . $this->db->escape(strtolower($keyword)) . "%' OR LCASE(pd.description) LIKE '%" . $this->db->escape(strtolower($keyword)) . "%'";
			}
			
			if (!$model) {
				$sql .= ")";
			} else {
				$sql .= " OR LCASE(p.model) LIKE '%" . $this->db->escape(strtolower($keyword)) . "%')";
			}
I will try to solve it out a little bit later. Oh, and yes, I need to include updates in the first post :) Cheers.

Diagonal. Tires for 2-wheelers.
http://www.diagonal-opony.pl
OC 1.4.9.4


User avatar
Newbie

Posts

Joined
Sat Feb 26, 2011 5:35 am
Location - Olsztyn, Poland

Post by marc_cole » Sun Feb 27, 2011 7:50 am

bald wrote:Okay, it's been a party evening tonight, but I see that there's kind of difference in our product.php files.
Could you check your catalog/model/catalog/product.php file, at line 180.
Sorry, my fault. :-[ I forgot that I had made changes to that file because of this thread:
http://forum.opencart.com/viewtopic.php?f=24&t=24391
I'll work around those changes and retry later.

OpenCart v1.4.9.4
VQMod | Categories Home | Cleaner By Default - 2 Column | Speak Good English


Active Member

Posts

Joined
Tue Dec 14, 2010 11:26 am
Location - Seattle, WA

Post by oliviargi » Sun Apr 17, 2011 2:30 pm

thanks guys

Newbie

Posts

Joined
Thu Mar 31, 2011 8:58 am

Post by dpsnw » Tue May 24, 2011 4:48 am

Hello, I think you did a great job on the MOD! But I was wondering if you could help me. Most of the items I sell are HP brand, so people wills earch for HP 4000 or HP 4050 toner or something like that, then they will get results for everything I sell and its not sorted by relevance!! So the first page has nothing to do with 4000's or 4050's.

I know that relevance is a completely different cat, but is there anyway to search for products that have to contain both keywords yet be in any order? For example: I search for "4000 HP" OR "HP 4000", and it will bring up only products iwth both keywords.

Thanks for the help!

New member

Posts

Joined
Tue May 24, 2011 4:44 am

Post by bald » Tue May 24, 2011 6:43 pm

I use this modification on my live cart and it indeed works the way you wanted yours to work.

Put any keywords in any order into searchbox and the result will give you products containing all wanted words (name + model in my example) whatever the order.

Diagonal. Tires for 2-wheelers.
http://www.diagonal-opony.pl
OC 1.4.9.4


User avatar
Newbie

Posts

Joined
Sat Feb 26, 2011 5:35 am
Location - Olsztyn, Poland

Post by dpsnw » Wed May 25, 2011 12:44 am

hmm, perhaps I did something wrong.

So if you had 2 items in your store, one named "blue water" and one named "blue sky", if I searched for blue sky would it come up with both? Because thats the issue Im having. I can currently put words in any order and it will search, but it will bring up everything with blue when I want it to only show things that contain both words I typed in.

I dont know if I tinkered with something wrong, but it seems like its running a "or" statement instead of an "and" statement.

New member

Posts

Joined
Tue May 24, 2011 4:44 am

Post by dpsnw » Wed May 25, 2011 1:09 am

One thing i've noticed is if you put commas after each word, it accomplishes what I need it to do. do you know of any way I can have it automatically insert commas after each keyword once the search is submitted?

New member

Posts

Joined
Tue May 24, 2011 4:44 am

Post by bald » Wed May 25, 2011 3:40 am

I don't remember if I changed anything in the mod without posting changes here. But I'll show you how it works on my website:

I have a few brands of tires. First let's look for Maxxises
http://www.diagonal-opony.pl/index.php? ... is&model=1
We get 4 pages of Maxxis products (different models).

Now, let's look for eg. M6001 model of maxxis
http://www.diagonal-opony.pl/index.php? ... 01&model=1
We got only 5 products, keywords divided just by space, order doesn't matter:
http://www.diagonal-opony.pl/index.php? ... is&model=1
Still same result.

As you can see it works. I have my mod running gud on 1.4.9.4. Perhaps this is the issue or maybe you have some other mods applied into the files. Check on vqmod logs.

Take care.

Diagonal. Tires for 2-wheelers.
http://www.diagonal-opony.pl
OC 1.4.9.4


User avatar
Newbie

Posts

Joined
Sat Feb 26, 2011 5:35 am
Location - Olsztyn, Poland
Who is online

Users browsing this forum: No registered users and 5 guests