Unix Technical Forum

SEO

vBulletin Search Engine Optimization


Go Back   Unix Technical Forum > Database Server Software > MySQL > MySQL General forum

Register FAQ Members List Calendar Search Today's Posts Mark Forums Read
  #1 (permalink)  
Old 02-28-2008, 06:19 AM
Daevid Vincent
 
Posts: n/a
Default How do I find products when a user types freeform strings like 'Sony 20" TV' or '20" Sony TV'?

I'm having trouble figuring out the logic/query I want.
I know that all those "OR"s are not right.
I'm doing this in PHP and mySQL (of course),
so if it can't be done with a single query, I can split it up.

Here's the challenge, given a text field search box, someone enters:

Sony 20" TV

How do I search for that, not knowing which fields are which?
For example, they could have also entered:

20" Sony TV

This is the one I have now, but (as you probably noticed), it will return many rows,
I expect that most of the time > 1 row will be returned, but I'm getting a grip more than I want (or the customer would want), and
also rows that have nothing to do with the search terms.

SELECT products.*, companies.name AS company_name, categories.name AS category_name
FROM products
LEFT JOIN companies ON company_id = companies.id
LEFT JOIN categories ON category_id = categories.id
WHERE products.enabled = 1
AND(
(products.model LIKE 'sony%' OR products.model LIKE '20%' OR products.model LIKE 'tv%')
OR (products.upc LIKE 'sony' OR products.upc LIKE '20' OR products.upc LIKE 'tv')
OR (products.name LIKE '%sony%' OR products.name LIKE '20%' OR products.name LIKE '%tv%')
OR (companies.name LIKE 'sony%' OR companies.name LIKE '20%' OR companies.name LIKE 'tv%')
OR (categories.name LIKE '%sony%' OR categories.name LIKE '20%' OR categories.name LIKE '%tv%')
)
ORDER BY categories.name DESC, products.name ASC, companies.name ASC;

(and that just gets uglier the more words in the search)

+----+------------------+--------------+--------------+---------------+
| id | name | model | company_name | category_name |
+----+------------------+--------------+--------------+---------------+
| 1 | 20" TV | STV20-KVR-HD | Sony | Tube | <---
| 2 | 36" TV | STV36-KVR-HD | Sony | Tube |
| 4 | Ultra-Plasma 62" | UP62F900 | Sony | Plasma |
| 5 | Value Plasma 38" | VPR542_38 | Sony | Plasma |
| 6 | Power-MP3 5gb | 09834wuw34 | Sony | MP3 Players |
| 3 | Super-LCD 42" | SLCD42hd002 | Sony | LCD |
| 7 | Super-Player 1gb | SP1gb | Sony | Flash |
| 8 | Porta CD | pcd500 | Sony | CD Players |
.......
+----+------------------+--------------+--------------+---------------+

Obviously the person wanted id = 1 in this case.

Unrelated, is there any speed improvement using JOIN instead of LEFT JOIN ?
Think millions of products.

Thanks for help and suggestions...

Daevid.

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #2 (permalink)  
Old 02-28-2008, 06:19 AM
Mogens Melander
 
Posts: n/a
Default Re: How do I find products when a user types freeform strings like'Sony 20" TV' or '20" Sony TV'?


On Fri, May 4, 2007 10:21, Daevid Vincent wrote:
> I'm having trouble figuring out the logic/query I want.
> I know that all those "OR"s are not right.
> I'm doing this in PHP and mySQL (of course),
> so if it can't be done with a single query, I can split it up.
>
> Here's the challenge, given a text field search box, someone enters:
>
> Sony 20" TV
>
> How do I search for that, not knowing which fields are which?
> For example, they could have also entered:
>
> 20" Sony TV
>


How about:

select soundex('Sony 20" TV' ),soundex('20" Sony TV');

'S531', 'S531'

--
Later

Mogens Melander
+45 40 85 71 38
+66 870 133 224



--
This message has been scanned for viruses and
dangerous content by OpenProtect(http://www.openprotect.com), and is
believed to be clean.

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #3 (permalink)  
Old 02-28-2008, 06:19 AM
Baron Schwartz
 
Posts: n/a
Default Re: How do I find products when a user types freeform strings like'Sony 20" TV' or '20" Sony TV'?

Hi Daevid,

Daevid Vincent wrote:
> I'm having trouble figuring out the logic/query I want.
> I know that all those "OR"s are not right.
> I'm doing this in PHP and mySQL (of course),
> so if it can't be done with a single query, I can split it up.
>
> Here's the challenge, given a text field search box, someone enters:
>
> Sony 20" TV
>
> How do I search for that, not knowing which fields are which?
> For example, they could have also entered:
>
> 20" Sony TV


I think you're describing full-text indexing. MySQL supports it but only on MyISAM
tables. If you don't want to use MyISAM, full-text search engines like Lucene or
Sphinx may be worth looking at.

Baron
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #4 (permalink)  
Old 02-28-2008, 06:20 AM
Daevid Vincent
 
Posts: n/a
Default RE: How do I find products when a user types freeform strings like 'Sony 20" TV' or '20" Sony TV'?

> -----Original Message-----
> From: Baron Schwartz [mailto:baron@xaprb.com]
>
> Daevid Vincent wrote:
> > I'm having trouble figuring out the logic/query I want.
> > I know that all those "OR"s are not right.
> > I'm doing this in PHP and mySQL (of course),
> > so if it can't be done with a single query, I can split it up.
> >
> > Here's the challenge, given a text field search box, someone enters:
> >
> > Sony 20" TV
> >
> > How do I search for that, not knowing which fields are which?
> > For example, they could have also entered:
> >
> > 20" Sony TV

>
> I think you're describing full-text indexing. MySQL supports
> it but only on MyISAM
> tables. If you don't want to use MyISAM, full-text search
> engines like Lucene or Sphinx may be worth looking at.


I don't think I am. While full-text indexing might help since
the indexes would be faster. I think this is a logic issue.

The full-text index would be useful on a TEXT or BLOB or some
long varchar field, but it doesn't solve that I'm trying to
pull from two different tables, Product and Company and mapping
the free-form string to fields that could be one of several.

I think my first attempt is close, but it's something to do with
all the AND and OR combinations that's not right.

My version gives many results because it matches ("SONY" OR "TV" OR "20").
I need it to match ("SONY" AND "TV" AND "20")

But this isn't it either (returns 0 results) because some fields,
like the categories.name, products.upc and products.model don't match
so the entire condition fails.

SELECT products.*, companies.name AS company_name, categories.name AS category_name
FROM products
LEFT JOIN companies ON company_id = companies.id
LEFT JOIN categories ON category_id = categories.id
WHERE products.enabled = 1
AND(
(products.model LIKE 'sony%' OR products.model LIKE '20%' OR products.model LIKE 'tv%')
AND (products.upc LIKE 'sony' OR products.upc LIKE '20' OR products.upc LIKE 'tv')
AND (products.name LIKE '%sony%' OR products.name LIKE '20%' OR products.name LIKE '%tv%')
AND (companies.name LIKE 'sony%' OR companies.name LIKE '20%' OR companies.name LIKE 'tv%')
AND (categories.name LIKE '%sony%' OR categories.name LIKE '20%' OR categories.name LIKE '%tv%')
)
ORDER BY categories.name DESC, products.name ASC, companies.name ASC;

Also, the 'SONY' is really the companies.name,
while the '20"' _AND_ 'TV' together form '20" TV' to make the products.name.

+------------------+--------------+--------------+--------------+
| name | model | upc | company_name |
+------------------+--------------+--------------+--------------+
| 20" TV | STV20-KVR-HD | 097855008633 | Sony |
| 36" TV | STV36-KVR-HD | 087452047023 | Sony |
.....
+------------------+--------------+--------------+--------------+

One way might be to do three separate queries, one for each word.
Then store them in an array and compare the overlaps, removing
any that aren't shared. Then a final query where product.id IN(array)

That seems extremely inefficient and hackish though.

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #5 (permalink)  
Old 02-28-2008, 06:20 AM
Baron Schwartz
 
Posts: n/a
Default Re: How do I find products when a user types freeform strings like'Sony 20" TV' or '20" Sony TV'?

Hi Daevid,

Daevid Vincent wrote:
>> -----Original Message-----
>> From: Baron Schwartz [mailto:baron@xaprb.com]
>>
>> Daevid Vincent wrote:
>>> I'm having trouble figuring out the logic/query I want.
>>> I know that all those "OR"s are not right.
>>> I'm doing this in PHP and mySQL (of course),
>>> so if it can't be done with a single query, I can split it up.
>>>
>>> Here's the challenge, given a text field search box, someone enters:
>>>
>>> Sony 20" TV
>>>
>>> How do I search for that, not knowing which fields are which?
>>> For example, they could have also entered:
>>>
>>> 20" Sony TV

>> I think you're describing full-text indexing. MySQL supports
>> it but only on MyISAM
>> tables. If you don't want to use MyISAM, full-text search
>> engines like Lucene or Sphinx may be worth looking at.

>
> I don't think I am. While full-text indexing might help since
> the indexes would be faster. I think this is a logic issue.
>
> The full-text index would be useful on a TEXT or BLOB or some
> long varchar field, but it doesn't solve that I'm trying to
> pull from two different tables, Product and Company and mapping
> the free-form string to fields that could be one of several.
>
> I think my first attempt is close, but it's something to do with
> all the AND and OR combinations that's not right.
>
> My version gives many results because it matches ("SONY" OR "TV" OR "20").
> I need it to match ("SONY" AND "TV" AND "20")
>
> But this isn't it either (returns 0 results) because some fields,
> like the categories.name, products.upc and products.model don't match
> so the entire condition fails.
>
> SELECT products.*, companies.name AS company_name, categories.name AS category_name
> FROM products
> LEFT JOIN companies ON company_id = companies.id
> LEFT JOIN categories ON category_id = categories.id
> WHERE products.enabled = 1
> AND(
> (products.model LIKE 'sony%' OR products.model LIKE '20%' OR products.model LIKE 'tv%')
> AND (products.upc LIKE 'sony' OR products.upc LIKE '20' OR products.upc LIKE 'tv')
> AND (products.name LIKE '%sony%' OR products.name LIKE '20%' OR products.name LIKE '%tv%')
> AND (companies.name LIKE 'sony%' OR companies.name LIKE '20%' OR companies.name LIKE 'tv%')
> AND (categories.name LIKE '%sony%' OR categories.name LIKE '20%' OR categories.name LIKE '%tv%')
> )
> ORDER BY categories.name DESC, products.name ASC, companies.name ASC;
>
> Also, the 'SONY' is really the companies.name,
> while the '20"' _AND_ 'TV' together form '20" TV' to make the products.name.
>
> +------------------+--------------+--------------+--------------+
> | name | model | upc | company_name |
> +------------------+--------------+--------------+--------------+
> | 20" TV | STV20-KVR-HD | 097855008633 | Sony |
> | 36" TV | STV36-KVR-HD | 087452047023 | Sony |
> ....
> +------------------+--------------+--------------+--------------+
>
> One way might be to do three separate queries, one for each word.
> Then store them in an array and compare the overlaps, removing
> any that aren't shared. Then a final query where product.id IN(array)
>
> That seems extremely inefficient and hackish though.


I misunderstood what you meant at first.

So, you want rows where all words appear in the row, rather than where all words appear
in any one column. How about this: every time you get a match on a term in any column,
count it as 1. Then add all these and compare to the number of words in your search
input, which you can determine either in SQL with a little text wrangling, or probably
more easily in whatever the client code is with a split() or similar.

SELECT products.*, companies.name AS company_name, categories.name AS category_name
FROM products
LEFT JOIN companies ON company_id = companies.id
LEFT JOIN categories ON category_id = categories.id
WHERE products.enabled = 1
AND(
(products.model LIKE 'sony%' + products.model LIKE '20%' products.model LIKE
'tv%')
+ (products.upc LIKE 'sony' + products.upc LIKE '20' + products.upc LIKE 'tv')
+ (products.name LIKE '%sony%' + products.name LIKE '20%' + products.name LIKE
'%tv%')
+ (companies.name LIKE 'sony%' + companies.name LIKE '20%' + companies.name LIKE
'tv%')
+ (categories.name LIKE '%sony%' + categories.name LIKE '20%' + categories.name LIKE
'%tv%')
)
>= [$number_of_words_in_input]

ORDER BY categories.name DESC, products.name ASC, companies.name ASC;

This will be ugly and inefficient though. It might be better to build and maintain a
separate table with the concatenation of all the fields, and fulltext index that.

Baron
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #6 (permalink)  
Old 02-28-2008, 06:20 AM
Mayssam Sayyadian
 
Posts: n/a
Default Re: How do I find products when a user types freeform strings like 'Sony 20" TV' or '20" Sony TV'?

Daevid,
It occurs to me that what you were explaining was multi-column keyword
search which MySQL does not support as of now. You may even face scenarios
where you need multi-table and multi-column keyword search (even in your
example, this may come up). In brief, you have a set of keywords and you
don't know in which column of a table they may appear (multi-column
kw-search), or you don't know in which (joined) tables they may appear
(multi-table kw-search).

I am working on a generic module to do this, however not sure when that
would be available. Meanwhile what you can do, given that you're doing
PHP+MySQL is to use free-text indexes on multiple textual columns, then
write a php module that would iterate over the columns, runs keyword search
on single column, then integrates the results. This will not be efficient,
but as of now, this type of logical keyword search must be handled outside
the database, I guess ...

--mayssam



On 5/4/07, Daevid Vincent <daevid@daevid.com> wrote:
>
> > -----Original Message-----
> > From: Baron Schwartz [mailto:baron@xaprb.com]
> >
> > Daevid Vincent wrote:
> > > I'm having trouble figuring out the logic/query I want.
> > > I know that all those "OR"s are not right.
> > > I'm doing this in PHP and mySQL (of course),
> > > so if it can't be done with a single query, I can split it up.
> > >
> > > Here's the challenge, given a text field search box, someone enters:
> > >
> > > Sony 20" TV
> > >
> > > How do I search for that, not knowing which fields are which?
> > > For example, they could have also entered:
> > >
> > > 20" Sony TV

> >
> > I think you're describing full-text indexing. MySQL supports
> > it but only on MyISAM
> > tables. If you don't want to use MyISAM, full-text search
> > engines like Lucene or Sphinx may be worth looking at.

>
> I don't think I am. While full-text indexing might help since
> the indexes would be faster. I think this is a logic issue.
>
> The full-text index would be useful on a TEXT or BLOB or some
> long varchar field, but it doesn't solve that I'm trying to
> pull from two different tables, Product and Company and mapping
> the free-form string to fields that could be one of several.
>
> I think my first attempt is close, but it's something to do with
> all the AND and OR combinations that's not right.
>
> My version gives many results because it matches ("SONY" OR "TV" OR "20").
> I need it to match ("SONY" AND "TV" AND "20")
>
> But this isn't it either (returns 0 results) because some fields,
> like the categories.name, products.upc and products.model don't match
> so the entire condition fails.
>
> SELECT products.*, companies.name AS company_name, categories.name AS
> category_name
> FROM products
> LEFT JOIN companies ON company_id = companies.id
> LEFT JOIN categories ON category_id = categories.id
> WHERE products.enabled = 1
> AND(
> (products.model LIKE 'sony%' OR products.model LIKE
> '20%' OR products.model LIKE 'tv%')
> AND (products.upc LIKE 'sony' OR products.upc LIKE '20'
> OR products.upc LIKE 'tv')
> AND (products.name LIKE '%sony%' OR products.name LIKE '20%'
> OR products.name LIKE '%tv%')
> AND (companies.name LIKE 'sony%' OR companies.name LIKE
> '20%' OR companies.name LIKE 'tv%')
> AND (categories.name LIKE '%sony%' OR categories.name LIKE '20%'
> OR categories.name LIKE '%tv%')
> )
> ORDER BY categories.name DESC, products.name ASC, companies.name ASC;
>
> Also, the 'SONY' is really the companies.name,
> while the '20"' _AND_ 'TV' together form '20" TV' to make the
> products.name.
>
> +------------------+--------------+--------------+--------------+
> | name | model | upc | company_name |
> +------------------+--------------+--------------+--------------+
> | 20" TV | STV20-KVR-HD | 097855008633 | Sony |
> | 36" TV | STV36-KVR-HD | 087452047023 | Sony |
> ....
> +------------------+--------------+--------------+--------------+
>
> One way might be to do three separate queries, one for each word.
> Then store them in an array and compare the overlaps, removing
> any that aren't shared. Then a final query where product.id IN(array)
>
> That seems extremely inefficient and hackish though.
>
>
> --
> MySQL General Mailing List
> For list archives: http://lists.mysql.com/mysql
> To unsubscribe: http://lists.mysql.com/mysql?unsub=i.mayssam@gmail.com
>
>


Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #7 (permalink)  
Old 02-28-2008, 06:22 AM
Iain Alexander
 
Posts: n/a
Default Re: How do I find products when a user types freeform strings like 'Sony 20" TV' or '20" Sony TV'?

On 4 May 2007 at 1:21, Daevid Vincent wrote:

> I'm having trouble figuring out the logic/query I want.
> I know that all those "OR"s are not right.

[snip]
> WHERE products.enabled = 1
> AND(
> (products.model LIKE 'sony%' OR products.model LIKE '20%' OR products.model LIKE 'tv%')
> OR (products.upc LIKE 'sony' OR products.upc LIKE '20' OR products.upc LIKE 'tv')
> OR (products.name LIKE '%sony%' OR products.name LIKE '20%' OR products.name LIKE '%tv%')
> OR (companies.name LIKE 'sony%' OR companies.name LIKE '20%' OR companies.name LIKE 'tv%')
> OR (categories.name LIKE '%sony%' OR categories.name LIKE '20%' OR categories.name LIKE '%tv%')
> )

[snip]

It seems to me that the logic you're looking for is something more like

(products.model LIKE 'sony%' OR products.upc LIKE 'sony' OR
products.name LIKE '%sony%' OR companies.name LIKE 'sony%' OR
categories.name LIKE '%sony%'
) AND (
products.model LIKE '20%' OR products.upc LIKE '20' OR
products.name LIKE '20%' OR companies.name LIKE '20%' OR
categories.name LIKE '20%'
) AND (
products.model LIKE 'tv%' OR products.upc LIKE 'tv' OR
products.name LIKE '%tv%' OR companies.name LIKE 'tv%' OR
categories.name LIKE '%tv%'
)

so that each of the search terms appears in at least one of the relevant
columns.
--
Iain Alexander ia@stryx.demon.co.uk


Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #8 (permalink)  
Old 02-28-2008, 06:22 AM
Daevid Vincent
 
Posts: n/a
Default RE: How do I find products when a user types freeform strings like 'Sony 20" TV' or '20" Sony TV'?

> -----Original Message-----
> From: Iain Alexander [mailto:ia@stryx.demon.co.uk]
> Sent: Wednesday, May 09, 2007 3:11 PM
> To: mysql@lists.mysql.com
> Subject: Re: How do I find products when a user types
> freeform strings like 'Sony 20" TV' or '20" Sony TV'?
>
> On 4 May 2007 at 1:21, Daevid Vincent wrote:
>
> > I'm having trouble figuring out the logic/query I want.
> > I know that all those "OR"s are not right.

> [snip]
> > WHERE products.enabled = 1
> > AND(
> > (products.model LIKE 'sony%' OR products.model

> LIKE '20%' OR products.model LIKE 'tv%')
> > OR (products.upc LIKE 'sony' OR products.upc LIKE

> '20' OR products.upc LIKE 'tv')
> > OR (products.name LIKE '%sony%' OR products.name

> LIKE '20%' OR products.name LIKE '%tv%')
> > OR (companies.name LIKE 'sony%' OR companies.name

> LIKE '20%' OR companies.name LIKE 'tv%')
> > OR (categories.name LIKE '%sony%' OR categories.name

> LIKE '20%' OR categories.name LIKE '%tv%')
> > )

> [snip]
>
> It seems to me that the logic you're looking for is something
> more like
>
> (products.model LIKE 'sony%' OR products.upc LIKE 'sony' OR
> products.name LIKE '%sony%' OR companies.name LIKE 'sony%' OR
> categories.name LIKE '%sony%'
> ) AND (
> products.model LIKE '20%' OR products.upc LIKE '20' OR
> products.name LIKE '20%' OR companies.name LIKE '20%' OR
> categories.name LIKE '20%'
> ) AND (
> products.model LIKE 'tv%' OR products.upc LIKE 'tv' OR
> products.name LIKE '%tv%' OR companies.name LIKE 'tv%' OR
> categories.name LIKE '%tv%'
> )
>
> so that each of the search terms appears in at least one of
> the relevant columns.


OMG! I think you are on to something. I just tried this, and I got one row. Exactly what I wanted. I'll have to poke at this some
more, and tweak my PHP that autogenerates the SQL, but I may just be naming my first born Iain.

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #9 (permalink)  
Old 02-28-2008, 06:22 AM
Daevid Vincent
 
Posts: n/a
Default RE: How do I find products when a user types freeform strings like 'Sony 20" TV' or '20" Sony TV'? [SOLVED]

> -----Original Message-----
> From: Daevid Vincent [mailto:daevid@daevid.com]
> Sent: Friday, May 04, 2007 1:22 AM
> To: mysql@lists.mysql.com
> Subject: How do I find products when a user types freeform
> strings like 'Sony 20" TV' or '20" Sony TV'?
>
> I'm having trouble figuring out the logic/query I want.
> I know that all those "OR"s are not right.
> I'm doing this in PHP and mySQL (of course),
> so if it can't be done with a single query, I can split it up.
>
> Here's the challenge, given a text field search box, someone enters:
>
> Sony 20" TV
>
> How do I search for that, not knowing which fields are which?
> For example, they could have also entered:
>
> 20" Sony TV
>
> This is the one I have now, but (as you probably noticed), it
> will return many rows,
> I expect that most of the time > 1 row will be returned, but
> I'm getting a grip more than I want (or the customer would want), and
> also rows that have nothing to do with the search terms.
>
> SELECT products.*, companies.name AS company_name,
> categories.name AS category_name
> FROM products
> LEFT JOIN companies ON company_id = companies.id
> LEFT JOIN categories ON category_id = categories.id
> WHERE products.enabled = 1
> AND(
> (products.model LIKE 'sony%' OR products.model
> LIKE '20%' OR products.model LIKE 'tv%')
> OR (products.upc LIKE 'sony' OR products.upc LIKE
> '20' OR products.upc LIKE 'tv')
> OR (products.name LIKE '%sony%' OR products.name
> LIKE '20%' OR products.name LIKE '%tv%')
> OR (companies.name LIKE 'sony%' OR companies.name
> LIKE '20%' OR companies.name LIKE 'tv%')
> OR (categories.name LIKE '%sony%' OR categories.name
> LIKE '20%' OR categories.name LIKE '%tv%')
> )
> ORDER BY categories.name DESC, products.name ASC, companies.name ASC;
>
> (and that just gets uglier the more words in the search)
>
> +----+------------------+--------------+--------------+-------
> --------+
> | id | name | model | company_name |
> category_name |
> +----+------------------+--------------+--------------+-------
> --------+
> | 1 | 20" TV | STV20-KVR-HD | Sony | Tube
> | <---
> | 2 | 36" TV | STV36-KVR-HD | Sony | Tube
> |
> | 4 | Ultra-Plasma 62" | UP62F900 | Sony |
> Plasma |
> | 5 | Value Plasma 38" | VPR542_38 | Sony |
> Plasma |
> | 6 | Power-MP3 5gb | 09834wuw34 | Sony | MP3
> Players |
> | 3 | Super-LCD 42" | SLCD42hd002 | Sony | LCD
> |
> | 7 | Super-Player 1gb | SP1gb | Sony | Flash
> |
> | 8 | Porta CD | pcd500 | Sony | CD
> Players |
> ......
> +----+------------------+--------------+--------------+-------
> --------+
>
> Obviously the person wanted id = 1 in this case.
>
> Unrelated, is there any speed improvement using JOIN instead
> of LEFT JOIN ?
> Think millions of products.
>
> Thanks for help and suggestions...
>
> Daevid.


I'll attach a .php file, but this list server may strip it off, so I'll also paste it below, sorry for any formatting issues in
advance...

<?php
if ($_POST['keywords'])
{
$_POST['keywords'] = stripslashes($_POST['keywords']);
$words = preg_split("/\s+/",$_POST['keywords'], -1, PREG_SPLIT_NO_EMPTY);
}

$sql = 'SELECT products.* FROM product_table WHERE 1 ';
$sql .= keyword_filter($words, array('products.model%', 'products.upc', '%products.name%', 'companies.name%', '%categories.name%'),
true);
$sth = SQL_QUERY($sql);

/**
* Builds the WHERE portion of a SQL statement using the keywords in various columns with wildcard support.
*
* @return string SQL statement fragment
* @param mixed $words either a string of words space deliminated or an array of words
* @param array $columns an array of table.column names to search the $words in. Use % as a wildcard for example pass in
'username%' or '%username%'.
* @param boolean $and (true) whether the words have to be ANDed or ORed together.
* @author Daevid Vincent [daevid@symcell.com]
* @since 1.0
* @version 1.4
* @date 05/10/07
* @todo This should handle +, - and "" just like google or yahoo or other search engines do.
*/
function keyword_filter($words, $columns, $and = true)
{
// this maybe useful
// http://wiki.ittoolbox.com/index.php/...ct_stateme nt
// http://www.ibiblio.org/adriane/queries/
// http://www.zend.com/zend/tut/tutoria...1&anc=0&view=1

// http://evolt.org/article/Boolean_Ful...665/index.html
// http://www.databasejournal.com/featu...le.php/3512461

// this would be great, but the dumb-asses don't work with InnoDB tables. GRRR!
// http://dev.mysql.com/doc/refman/5.0/...t-boolean.html
//$sql .= " AND MATCH (".implode(',',$columns).") AGAINST ('".implode(' ',$words)."' IN BOOLEAN MODE)";

if (!is_array($columns) or !$words) return;

if (is_string($words))
$words = preg_split("/\s+/",$words, -1, PREG_SPLIT_NO_EMPTY);

if(count($words) < 1) return '';

if ($and) //AND the words together
{
$sql = " AND ";
$sqlArray = array();
foreach($words as $word)
{
$tmp = array();
foreach($columns as $field)
{
$col = str_replace('%','',$field);
//[dv] read the http://php.net/preg_replace carefully. You must use this format,
// because otherwise $words that are digits will cause undesired results.
$myword = preg_replace("/(%)?([\w\.]+)(%)?/", "\${1}".$word."\${3}", $field );
$tmp[] = $col." LIKE '".SQL_ESCAPE($myword)."'";
}
$sqlArray[] = " (".implode(" OR ",$tmp).") ";
}
$sql .= implode(" AND ", $sqlArray);
}
else //OR the words together
{
$sql = " AND ( ";
$sqlArray = array();
foreach($columns as $field)
{
$col = str_replace('%','',$field);

$tmp = array();
foreach($words as $word)
{
//[dv] read the http://php.net/preg_replace carefully. You must use this format,
// because otherwise $words that are digits will cause undesired results.
$myword = preg_replace("/(%)?([\w\.]+)(%)?/", "\${1}".$word."\${3}", $field );
$tmp[] = $col." LIKE '".SQL_ESCAPE($myword)."'";
}
$sqlArray[] = "(".implode(" OR ",$tmp).") ";
}
$sql .= implode(" OR ", $sqlArray);
$sql .= ") ";
}

return $sql;
}
?>

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On
Forum Jump


All times are GMT. The time now is 05:07 AM.


Powered by vBulletin® Version 3.6.5
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
SEO by vBSEO 3.2.0
UnixAdminTalk.com

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291