Implementing MySQL full-text search
There comes a time in every developer's life when they are required to implement some sort of a search functionality. Most of us start with the easiest choice: a MySQL "like" query.
So, if someone searched for the term "I like bananas", the query probably looked something like this.
SELECT * FROM posts WHERE title LIKE '%I like bananas%'
That'll be alright for the most part, but wait. That's only good as long as you are looking for posts with titles encompassing that EXACT phrase. In other words, if there's a post with a title that contained "I like ripe bananas", it wouldn't get queried. Hmm...
Full-text search for the rescue!
So, what's a full-text search? It's a type of search that actually looks at each search keyword separately, and tries to match combinations of those keywords, as opposed to the exact phrase the user entered. In other words, it'll solve our problem above. (If you would like to read up more about full-text searching, check out this wikipedia article)
Alright, so what do we do next?
Let's say that the table that stores the posts is called "posts" and that you would like to run the search on the "title" (VARCHAR 255) and "description" (TEXT) fields of that table. (Note: If you have a field in BLOB format, you should first convert it to TEXT before proceeding)
- First, we need to add a fulltext index to the columns we would like to run the search on. In our example, you can do that by running this query
ALTER TABLE posts ADD FULLTEXT(title, description);
- Now that you have the fields indexed, add a few rows of data.
- Once you have around 5 - 6 rows (read the "Gotchas" section below for why this is important), run the following query
SELECT * FROM posts WHERE MATCH(title, description) AGAINST ('I love bananas')
Provided that you have the word "love" or "bananas" in any of the post titles or descriptions, this should pull them up.
It's that easy!
But, there are some very serious gotchas to be aware of:
- If your search term is too short, the search will NOT return anything. (I lost around 3 hours on this one). It turns out that MySQL has a lower limit on how many characters you need to enter in the search term before it even bothers doing a full-text search. There are 2 solutions to this problem. You can either tell the users via instructions (and/or using validations), that they need to enter at least x number of characters to perform a search. Or, you can revert to a "MySQL like" search when the search term is too small. Both are acceptable solutions depending on your particular scenario.To find out what this full-text search lower limit is, run the following query and look at the "ft_min_word_len" value.
show variables like 'ft_%'
- If the number of records you have is too few, MySQL will once again return an empty result set (Aargh... another 2 hours of my life down the drain!). So, make sure you have a decent number of rows first before running a full-text search query. I couldn't find any good documentation that pointed this little nugget out. I hope this post save someone else a few hours of their time.
- The way MySQL orders the results might be a bit weird in some cases. MySQL makes this decision based on a score that it internally assigns each result. You can print it out by doing the following query
SELECT *, MATCH(title, description) AGAINST ('I love bananas') AS score FROM posts WHERE MATCH(title, description) AGAINST('I love bananas')Basically, if the search term appears in ALL the rows, then MySQL has to take a call on what rows are more important than others. (Getting this one thing right is what makes Google such a great search engine!). Otherwise, it'll try to give a higher score to rows that contain more of the keywords than ones that don't. The best way to figure this out is by trying a few searches and analysing the scoring mechanism.
I wanted to keep this post simple, and not dvelve into things like binary and natural language searches. The idea was to point out a few crucial "gotchas" and start you off on the right path. You can find more information about full-text search at http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html.
>
