0

I'm currently trying to implement a search for keywords/tags in my db.

In my db, I have lines with keywords like: auto,cabrio,frischluft or hose,jeans,blaue hose,kleidung

so always some keywords (that can basically also have a whitespace), seperated by a comma (,).

Now I want to be able to find a product in my db that has some keywords entered.

With LIKE I can find the two entries I mentioned with queries like auto,cabrio or also cabrio,frischluft or hose,jeans,blau or hose,kleidung. But what happens if I enter auto,frischluft or something like hose,blaue hose or jeans,kleidung?

Then LIKE wont work any more. Is there a way to do this?

I hope you know what I mean...

So just to make it clear: The code I currently use is: $searchQuery = "%".$request->input('productSearch')."%"; and $products = Product::where('name', 'LIKE', $searchQuery)->paginate(15);

But as I said, this won't bring me back the article with the keyowrds auto,cabrio,frischluft if the input productSearch has the keywords auto,frischluft entered...

Any ideas?

2 Answers 2

4

Sorry, I know I'm late for the party but this is the first result in Google when I was looking for Eloquent keywords search. I had the same problem and I want to help with my solution.

$q = $request->input('productSearch');
$needles = explode(',', $q);

// In my case, I wanted to split the string when a comma or a whitespace is found:
// $needles = preg_split('/[\s,]+/', $q);

$products = Products::where('name', 'LIKE', "%{$q}%");

foreach ($needles as $needle) {
    $products = $products->orWhere('name', 'LIKE', "%{$needle}%");
}

$products = $products->paginate(15);

If the user input has too many commas, the $needles array could be too large (and the query too huge), so you can limit the search, for example, for only the first 5 elements in the array:

$needles = array_slice($needles, 0, 5);

I hope this can help somebody.

Sign up to request clarification or add additional context in comments.

Comments

0

On your reply just now:

If you want it simpler, read this MySQL documentation: https://dev.mysql.com/doc/refman/5.7/en/regexp.html.

Basically, in a file you could grep for [,]?blaue hose[,]? to find: an optional comma, the string 'blaue hose', and an optional comma.

The more solid solution would be my initial answer:

You could actually create a keyword table, depending on your products table, where each keyphrase/keyword is in one column by itself, and even lay an index on the keyphrase/keyword. I explain the principle here:

Optimising LIKE expressions that start with wildcards

And, to take your example as input - here is how I do that in Vertica. Many databases offer a function that returns the n-th part/token of a string delimited by a character of your choice. In Vertica, it's SPLIT_PART().

MySQL, unfortunately, does not offer any correspondence to that function, and you would have to convert the Common Table Expressions in the WITH clauses below to in-line SELECT-s (SELECT ... FROM (SELECT ... ) AS foo(col1,col2,col3) ..... And then, there is a suggestion here From Daniel Vassallo on how to tackle it:

Split value from one field to two

In Vertica, it would look like this:

WITH 
-- input
products(prod_id,keywords) AS (
          SELECT 1001,'auto,cabrio,frischluft'
UNION ALL SELECT 1002,'hose,jeans,blaue hose,kleidung'
)
,
-- index to get the n-th part of the comma delimited string
max_keyword_count(idx) AS (
          SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
)
SELECT
  prod_id
, idx
, TRIM(SPLIT_PART(keywords,',',idx)) AS keywords
FROM products
CROSS JOIN max_keyword_count
WHERE SPLIT_PART(keywords,',',idx) <> ''
ORDER BY
  prod_id
, idx
;

prod_id|idx|keywords
  1,001|  1|auto
  1,001|  2|cabrio
  1,001|  3|frischluft
  1,002|  1|hose
  1,002|  2|jeans
  1,002|  3|blaue hose
  1,002|  4|kleidung

8 Comments

Thx for the answer but this sounds very difficult.. Is there any easier way to do this?
In that case, read this MySQL documentation: dev.mysql.com/doc/refman/5.7/en/regexp.html . Basically, in a file you could grep for [,]?blaue hose[,]? to find: an optional comma, the string 'blaue hose', and an optional comma.
but this is basically what LIKE would do, too, isn't it? Because how could I use your idea when using hose,blaue hose? Should end in the product with the keywords hose,jeans,blaue hose,kleidung
If what you mean is that you give a list of keywords as input, and hope to find a match if you search for 'hose, blaue hose' in 'hose,jacke,jeans,blaue hose' - then this is not a SQL question you could ask. You would have to programmatically convert the search condition to WHERE keywords LIKE '%hose% OR keywords LIKE '%blaue hose%'.
okay, you might be right, but if I use an OR like you suggested now, I would run in the issue, that there would also be results that only contain hose or blaue hose, but not both together. But I think you got my idea. I have a product with a list of keywords, then I want to be able to pass a list of keywords to a search field and I want to find products that contain all keywords, passed from the search box, no matter in which order they are saved for the product
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.