I am using MySql FullText indexing to search data from database.
Here is the query
$search_input_text = 'the_string_to_be_search';
$searchArray = explode(" ", $search_input_text);
$query="SELECT * FROM car_details
WHERE MATCH (car_trim) AGAINST ('";
foreach ($searchArray as $word) {
$query .= "+".$word."* ";
}
$query .= "' IN BOOLEAN MODE) LIMIT $start, $limit";
The query is executing fine but it has a bug, if you look at the column name you will find car_trim which is inside the MATCH() function. The column has only 3 different types of values in the database which are 'T5', 'T6' and 'T5 premier'.
When I type 'Premier' in the search bar and hit Enter, it fetches the results whose values contain the word 'Premier'. But when I type T5 or T6 , it returns an empty record. Please be sure that there are lots of records with car_trim='T5', car_trim='T6' or car_trim='T5 Premier'
I am not getting that what can be the problem with the strings T5 and T6.
MySQL has two key parameters when using full text search (and a few other important ones). The key parameters are the minimum word length and the stop words list. In short, MySQL ignores words that are less than 3 or 4 characters (depending on the storage engine) or that are in the stop word list.
Your examples ("T5" and "T6") are too short -- based on the parameter defaults.
Some other configuration parameters might be of interest, such as the maximum word length and the characters that are valid for words.
You can change the parameters for full text indexing and re-build the index.
Here is a good place to start in understanding this.
Related
I'd like to get the most matched data from DB by split array in search query.
Imagine my query is: "How to buy a motorbike" & in DB I've enlisted some data like
buy a helicopter
buy a motorbike
buy a car
So, after split the query, it'll search into DB as "how", "to","buy", "motorbike" respectfully. Using these sub-strings, the query only generate "buy a helicopter" string in output. But I want to get buy a motorbike data. I generated a method but it only encode data when any of these sub-strings get matched with same data in DB.
Here's my code that fetch only first matched data but my desired data is in no. 2.
$str=$_POST['search'];
$str=preg_split("/[\s]+/", $str);
foreach ($str as $search ) {
$sql = "SELECT answer FROM query_tbl WHERE q1 like '%".$search."%' ";
$record = mysqli_query($link, $sql);
$rows=mysqli_fetch_assoc($record);
if ($rows == true) {
echo json_encode(array('ans'=>$rows['answer']));
}
}
So, which algorithm should i follow and where to use it to achieve my goal?
I think it would be best to do a full-text search as described here.
By default or with the IN NATURAL LANGUAGE MODE modifier, the MATCH() function performs a natural language search for a string against a text collection. A collection is a set of one or more columns included in a FULLTEXT index. The search string is given as the argument to AGAINST(). For each row in the table, MATCH() returns a relevance value; that is, a similarity measure between the search string and the text in that row in the columns named in the MATCH() list.
This is my code:
$sql = "SELECT *,MATCH (CUIT,DENOMINACION) AGAINST ('%{$word}%') AS Score FROM cuits WHERE";
$sql_end = '';
foreach($words as $word) {
$sql_end .= " AND MATCH (CUIT,DENOMINACION) AGAINST ('%{$word}%' IN BOOLEAN MODE) AND BAJA=0 ";
$sql_end2 = "order by DENOMINACION limit $inicio, $TAMANO_PAGINA";
}
It is very slow. How can I improve the speed?
It doesn't make sense in FULLTEXT search to use LIKE-style wildcard strings %. So, change AGAINST ('%{$word}%') to AGAINST ('{$word}') and see if it helps.
Also, FULLTEXT can match multiple words at once, so there's no need to repeat the whole MATCH clause for each word. Instead try
SELECT *,MATCH (CUIT,DENOMINACION) AGAINST ('word word word word') ...
You may, if the series of words is a phrase, wish to stop using the boolean FULLTEXT mode and use the natural language mode as shown in your first MATCH clause.
Be aware that FULLTEXT works very strangely indeed on small tables, with less than a few hundred rows. That makes testing on small tables difficult.
Finally, make sure your FULLTEXT index is constructed correctly.
I am running MySQL version 5.1.57
I have a HTML form where a user can insert a search-string. I create a $_SESSION on this string, then I run it in a MySQLquery. Something like this:
<?php
$sql = mysql_query ("SELECT
s.student_firstname, s.student_lastname
FROM students s
WHERE (
s.student_firstname LIKE '%$searchstring%' OR
s.student_lastname LIKE '%$searchstring%
)
AND s.isActive = '1' ");
?>
The problem is when a user is searching for multiple words. Then my query fails because it is trying to match the string against the values in either column.
I've read something about MySQL FULLTEXT indexing but as far as I understand, it only works on MyISAM tables(?). How can I be able to search for multiple words using the environment that I have?
I think you should split your searched string on space (" ") and insert each segment in your query, or in another query. For example :
$str = "word1 word2";
With that you search first for the whole string "word1 word2" and after you search in you database for "word1" and "word2".
With this solution you should handle a word ignore list, because words like "a, an, the, or, ..." shouldn't be seek ...
I'm not sure there is an other way with an innoDB table ... The best solution is obviously to use the "match against" command, but it's only available with a full text index under MyISAM.
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
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