Search table for keyword - php

I have a website that basicly consists on a video search engine, I have the follow code that will query mysql for the given input criteria:
$search=htmlspecialchars($_GET['load']);
$say=mysql_query("SELECT * FROM madvideo WHERE MATCH (baslik) AGAINST ('*$search*' IN BOOLEAN MODE)");
Then I have the follow code that will display the results:
$katala=mysql_query("SELECT * FROM madvideo WHERE MATCH (baslik) AGAINST ('*$search*' IN BOOLEAN MODE) order by id asc limit $s,$perpage");
$i=0;
while ($sea=mysql_fetch_array($katala)) {
$i++;
$idd=$sea['id']; $seoo=$sea['seo']; $baslikk=$sea['baslik']; $resimm=$sea['resim']; $suree=$sea['sure'];
$izlenmee=$sea['izlenme']; $tarihh=$sea['tarih']; $katt=$sea['kat'];
Let me try to explain what's the problem with this.
Lets say you search on my website for "I like to eat strawberry"
And lets suppose I have on mysql table an entry with the very same name "I like to eat strawberry"
With my current code I will get the follow example results:
"I like to drive my car"
"my car is super fast"
"they eat to much"
and so on, and the relevant result might appear but not at first like I would like to be.
How can I make it display the results in a more relevant way, like the google for example?

Break the search term into words so you can build the order by condition dynamically using like expressions. Since the result of a logic expression in mysql is 1 or 0 you can add those expressions.
SELECT *
FROM madvideo
WHERE MATCH (baslik) AGAINST ('*$search*' IN BOOLEAN MODE)
order by
(baslik like '%$word1%')
+ (baslik like '%word2%')
+ (baslik like '%word3%')
desc
limit $s,$perpage

Related

MySQL select only using first word of variable

I am using php and mySQL. I have a select query that is not working. My code is:
$bookquery = "SELECT * FROM my_books WHERE book_title = '$book' OR book_title_short = '$book' OR book_title_long = '$book' OR book_id = '$book'";
The code searches several title types and returns the desired reference most of the time, except when the name of the book starts with a numeral. Though rare, some of my book titles are in the form "2 Book". In such cases, the query only looks at the "2", assumes it is a "book_id" and returns the second entry in the database, instead of the entry for "2 Book". Something like "3 Book" returns the third entry and so forth. I am confused why the select is acting this way, but more importantly, I do not know how to fix it.
If you have a column in your table with a numeric data type (INT, maybe), then your search strategy is going to work strangely for values of $book that start with numbers. You have discovered this.
The following expression always returns true in SQL. It's not intuitive, but it's true.
99 = '99 Luftballon'
That's because, when you compare an integer to a string, MySQL implicitly does this:
CAST(stringvalue AS INT)
And, a cast of a string beginning with the text of an integer always returns the value of the integer. For example, the value of
CAST('99 Luftballon' AS INT)
is 99. So you'll get book id 99 if you look for that search term.
It's pointless to try to compare an INT column to a text string that doesn't start with an integer, because CAST('blah blah blah' AS INT) always returns zero. To make your search strategy work better, you should consider omitting OR book_id = '$book' from your search query unless you know that the entirety of $book is a number.
As others mention, my PHP allowed both numerical enties and text entries from the browser. My query was then having a hard time with this, interpreting some of my text entries as numbers by truncating the end. Thus, my "2 Book" was being interpreted as the number "2" and then being queried to find the second book in the database. To fix this I just created a simple if statement in PHP so that my queries only looked for text or numbers. Thus, in my case, my solution was:
if(is_numeric($book)){
$bookquery = "SELECT * FROM books WHERE book_id = '$book'";
}else{
$bookquery = "SELECT * FROM books WHERE book_title = '$book' OR book_title_short = '$book' OR book_title_long = '$book'";
}
This is working great and I am on my way coding happily again. Thanks #OllieJones and others for your questions and ideas which helped me see I needed to approach the problem differently.
Not sure if this is the correct answer for you but it seems like you are searching for only exact values in your select. Have you thought of trying a more generic search for your criteria? Such as...
$bookquery = "SELECT * FROM my_books WHERE book_title LIKE '".$book."' OR book_title_short LIKE '".$book."' OR book_title_long LIKE '".$book."' OR book_id LIKE '".$book."'"
If you are doing some kind of searching you might even want to ensure the characters before the search key are found as well like so....
$bookquery = "SELECT * FROM my_books WHERE book_title LIKE '%".$book."' OR book_title_short LIKE '%".$book."' OR book_title_long LIKE '%".$book."' OR book_id LIKE '%".$book."'"
The % is a special char that looks for allows you to search for the chars you want to search for PLUS any characters before this that aren't in the search criteri... for example $book = "any" with a % before hand in the query like so, '%".$book."'"`` would return bothcompanyand also the wordany` by itself.
If you need to you can add a % to the end also like so, `'%".$book."%'"`` and it would do the same for the beginning and end of the search key

MATCH ... AGAINST doesn't come up with exact results

I'm working for the first time with MATCH...AGAINST in php sql but there is one bothering me and I can't figure out how to fix it. This is my code:
SELECT * FROM m_artist WHERE match(artist_name) against('". $_POST['article_content'] ."' IN BOOLEAN MODE)
And this is $_POST['article_content']:
Wildstylez Brothers Yeah Frontliner Waveliner
Now my output should be: Wildstylez, Frontliner and Waveliner cause that's in my database. And I do but besides that I also get the Vodka Brothers, 2 Brothers of Hardstyle and more cause of the word brothers. How do I fix that SQL only selects the literal match?
Full-text search actually is a quite misleading name: you can search the full text by your query (like google does) but it won't guarantee you, that the full text equals your query.
So, according to documentation on Boolean Full-Text Searches your input Wildstylez Brothers Yeah Frontliner Waveliner is interpreted as artist_name contains (at least) one of Wildstylez, Brothers, Yeah, Frontliner and Waveliner as word. This is why you get e.g. the Vodka Brothers, which contains Brothers. For google-like purposes this is just what you want, as you want to get details on something you only know part of as in show me articles on music.
You probably want to use
artist_name LIKE '%name_part1%' OR artist_name LIKE '%name_part2%' ...
or
artist_name IN ('exact_name1', 'exact_name2', ...)
simpliest case would be doing something like
$names = explode(' ', $_POST['article_content']);
$name_searches = array_map(function($a) {return 'artist_name = \''.mysql_real_escape_string($a).'\'';}, $names);
$sql = "SELECT * FROM m_artist WHERE ".implode(" OR ", $name_searches);
but you would loose the ability to find 2 Brothers of Hardstyle as the name itself contains a space.
Another approach can be to prefix all words by '+' and stick to MATCH() AGAINST() and you will find only artists which include every word given.
Please provide more context if this is not what you are looking for.

How do I search Full text with partial matches?

I have a table, with not many rows, and neither many columns. I am doing a Full text search on 3 columns.
My code is
$search_input = trim($_GET['s']);
$search = mysql_real_escape_string($search_input);
$search = '+'.str_replace(' ', '* +', $search).'*';
$sql = "SELECT * FROM table WHERE
MATCH(def, pqr, xyz) AGAINST ('$search' IN BOOLEAN MODE)";
$result = mysql_query($sql);
I can correctly search for terms like abcdefgh, which are present as ... abcdefgh ....
But I am receiving empty set with search terms like abc, where in table entry is present something like abc-123, and also terms like abcdefghs. (notice this is plural of above)
Clearly I need to implement partial search, or something like that.
But how do I implement such a search? Any better way to do a entire table search on user input?
Do mention anything I am doing incorrectly.
EDIT : By adding * after each word, now I am able to also search for abcde, but above problems remains.
Do you mean you don't get results for 3 letter combinations? If so, you might be hitting the mysql index length (which is usually set to 3)
More info here - http://dev.mysql.com/doc/refman/5.1/en/fulltext-fine-tuning.html

Php/mysql search engine

How I do exact match or anywhere match keywords on the table with php/mysql search engine.
For example: i added a url with keywords: UFC 131 online
And 2nd url with keywords: UFC 132 online
and if i enter UFC 132 on the search box how do i make the 2nd url to come up first?
Because if i use this code
//explode out search term
$search_exploded = explode(" ",$search);
foreach($search_exploded as $search_each)
{
//construct query
$x++;
if ($x==1)
$construct .= "title LIKE '%$search_each%'";
else
$construct .= " or title = '$search'";
and i search for ufc 132 online it gives me ufc 131 online result first.
You could implement something like this:
SELECT *, MATCH (title) AGAINST ('searchstring' IN BOOLEAN MODE) +
CASE
WHEN title = 'searchstring' THEN 10
ELSE 0
END AS relevance FROM `wrestlingsucks`
HAVING relevance > 1.0
ORDER BY relevance DESC LIMIT 100
This is a very basic example, all it will do is add 10 to a sudo relevance column if its an exact match. You could however get as complicated as you want with full text and natural matching.
MySQL has superior search capabilities for full text search than handcrafting your searches. Take a look at fulltext-search
From the documentation MATCH (col1,col2,...) AGAINST (expr [search_modifier])
Use Levenshtein algorithm in MySQL.
Levenshtein matching is a metric for
measuring the amount of difference
between two sequence, here it is
strings. By default MySQL does not
have this function, but you can write
and add one.
Please take a look at the code here and add that code as a system function in MySQL, please see the example below on how to get the similarity of two strings.
Please see: https://github.com/rakesh-sankar/Tools/blob/master/MySQL/Levenshtein.txt
Example: SELECT column1,
LEVENSHTEIN(column1, 'matchme') AS
perfectmatch FROM sometable ORDER BY
perfectmatch DESC

Php/ MySql 'Advanced Search' Page

I'm working on an 'advanced search' page on a site where you would enter a keyword such as 'I like apples' and it can search the database using the following options:
Find : With all the words, With the
exact phrase , With at least one of
the words, Without the words
I can take care of the 'Exact phrase' by:
SELECT * FROM myTable WHERE field='$keyword';
'At least one of the words' by:
SELECT * FROM myTable WHERE field LIKE '%$keyword%';//Let me know if this is the wrong approach
But its the 'With at least one of the words' and 'Without the words' that I'm stuck on.
Any suggestions on how to implement these two?
Edit: Regarding 'At least one word' it wouldn't be a good approach to use explode() to break the keywords into words, and run a loop to add
(field='$keywords') OR ($field='$keywords) (OR)....
Because there are some other AND/OR clauses in the query also and I'm not aware of the maximum number of clauses there can be.
I would suggest the use of MySQL FullText Search using this with the Boolean Full-Text Searches functionality you should be able to get your desired result.
Edit:
Requested example based on your requested conditions ("Its just one field and they can pick either of the 4 options (i.e 1 word, exact words, at least 1 word, without the term).")
I am assuming you are using php based on your initial post
<?php
$choice = $_POST['choice'];
$query = $_POST['query'];
if ($choice == "oneWord") {
//Not 100% sure what you mean by one word but this is the simplest form
//This assumes $query = a single word
$result = mysql_query("SELECT * FROM table WHERE MATCH (field) AGAINST ('{$query}' IN BOOLEAN MODE)");
} elseif ($choice == "exactWords") {
$result = mysql_query("SELECT * FROM table WHERE MATCH (field) AGAINST ('\"{$query}\"' IN BOOLEAN MODE)");
} elseif ($choice == "atLeastOneWord") {
//The default with no operators if given multiple words will return rows that contains at least one of the words
$result = mysql_query("SELECT * FROM table WHERE MATCH (field) AGAINST ('{$query}' IN BOOLEAN MODE)");
} elseif ($choice == "withoutTheTerm") {
$result = mysql_query("SELECT * FROM table WHERE MATCH (field) AGAINST ('-{$query}' IN BOOLEAN MODE)");
}
?>
hope this helps for full use of the operators in boolean matches see Boolean Full-Text Searches
You could use
With at least one of the words
SELECT * FROM myTable WHERE field LIKE '%$keyword%'
or field LIKE '%$keyword2%'
or field LIKE '%$keyword3%';
Without the word
SELECT * FROM myTable WHERE field NOT LIKE '%$keyword%';
I'm not sure you could easily do those search options in a naive manner as the other two.
It would be worth your while implementing a better search engine if you need to support those scenarios. A simple one that could probably get you by is something along these lines:
When an item is added to the database, it is split up into the individual words. At this point "common" words (the, a, etc...) are removed (probably based on a common_words table). The remaining words are added to a words table if they are not already present. There is then a link made between the word entry and the item entry.
When searching, it is then a case of getting the word ids from the word table and the appropriate lookup of item ids in the joining table.
Search is notoriously difficult to do well.
You should Consider using a third party search engine using something like Lucene or Sphider.
Giraffe and Re0sless pooseted 2 good answers.
notes:
"SELECT * " sucks... only select the columns that you need.
Re0sless puts a "OR" between keywords.
- you should eliminate common words (" ","i","am","and"..etc)
- mysql has a 8kb i belive limit on the size of the query, so for really long SELECTS you should slipt it into separate queries.
- try to eliminate duplicate keywords (if i search for "you know you like it" the SELECT should basically only search for "you" once and elimnate common words as "it")
Also try to use "LIKE" and "MATCH LIKE" (see mysql man page) it could do wonders for "fuzzy" searches

Categories