Только для читателей Lifeexample возможно открыть интернет-магазин на Moguta.CMS со скидкой в 15%
Полнотекстовый поиск MySQL
Здравствуйте, уважаемые читатели блога LifeExample, задача полнотекстового поиска по таблицам базы данных, является неотъемлемой, практически, для каждого веб-ресурса. Все новички рано или поздно сталкиваются с вопросом, "как реализовать полнотекстовый поиск по сайту?" конечно сначала задача всплывает несколько иначе: "как сделать поиск по сайту?".
Отличие обычного поиска от полнотекстового в том что, при первом искать сущности сайта, будь то товары магазина или статьи блога, можно по конкретному параметру, например по дате добавления. Полнотекстовый поиск, в свою очередь, подразумевает поиск по совпадающим ключевым словам запроса и текста искомого товара или статьи.
Самым наглядным примером полнотекстового поиска являются поисковые системы, такие как yandex.ru или google.ru, при вводе запроса "Полнотекстовый поиск MySQL" в поисковую строку система разобьет фразу на три слова:
- Полнотекстовый
- поиск
- MySQL
Затем проанализирует имеющиеся сущности, в данном случае это набор проиндексированных страниц сайтов, на наличие совпадений с каждым словом. Те страницы, которые имеют хотя бы одно из слов всей фразы либо их словоформ, будут выведены в поисковую выдачу.
Надо заметить, что поисковые системы обладают множеством алгоритмов позволяющих найти наиболее релевантную информацию по введенной фразе, но мы сегодня создадим самый простейший полнотекстовый поиск с помощью MySQL.
Как сделать полнотекстовый поиск MySQL
Какой бы не казалась задача полнотекстового поиска сложной, решается она очень быстро и просто. Беря в расчет, что сегодня большинство сайтов используют в качестве хранилища информации базу данных MySQL, то далее речь пойдет о реализации поиска по сайту именно по таблицам MySQL.
Реализовать поиск по таблицам MySQL можно разными способами:
- Оператор LIKE
- Оператор REGEXP
- Операторы AGAINST и MATCH
Первые два оператора самый примитивный вариант для поиска по сайту, и кроме того очень медлительный и требующий большой производительности сервера.
Поиск по сайту с помощью оператора LIKE
Например, реализовать поиск по таблице статей, используя оператор LIKE, можно следующим запросом:
1 | SELECT * FROM `aticle` WHERE `content` LIKE “%новость%” |
Данный запрос выдаст все записи, т.е. все статьи в тексте которых встретится слово "новость", если в содержании самой статьи нет данного слова, но оно в присутствует в заголовке, статья не будет найдена.
Чтобы искать статьи также и по совпадению в заголовках, можно усовершенствовать запрос:
1 2 3 4 | SELECT * FROM `aticle` WHERE `content` LIKE “%новость%” OR `title` LIKE “%новость%” |
Этот SQL запрос учитывает два текстовых поля, по которым произойдет поиск статьи, но использует уже несколько операторов LIKE, а это двойная нагрузка на сервер. Кроме того если пользователь запросит статьи по фразе "новость дня", то получи те статьи, которые содержат исключительно именно такую фразу: "новость дня".
MySql match – все что нужно для поиска по сайту
В арсенале программиста, использующего mysql, имеется стандартный инструмент для полнотекстового поиска MySql – операторы: MATCH и AGAINST.
Возьмем, к примеру, задачу поиска товаров по базе интернет магазина. Как правило, товар имеет ряд текстовых характеристик, таких как: название, описание, артикул, ключевые слова и др.
Используя для реализации полнотекстового поиска MATCH и AGAINST запрос может выглядит так:
1 2 | SELECT * FROM `product` WHERE MATCH(`meta_desc`, `meta_keywords`) AGAINST('Full') |
При этом, для работоспособности запроса должен существовать индекс таблицы товаров с типом FULLTEXT, объединяющий в себе перечень полей для поиска:

Имя индекса может быть любым, а в полях должны быть перечислены, все те, которые будут участвовать в поиске. При данном индексе, показанном на картинке, нельзя делать выборку только по одному из указанных полей.
WHERE MATCH(`meta_keywords`) – такой запрос выдаст ошибку и чтобы ее избежать нужно создать отдельный индекс и включить в него только одно поле (`meta_keywords`).
Для поиска части строки, а не строгого соответствия , нужно использовать модификатор INBOOLEANMODE и символ ‘*‘:
1 2 3 4 5 | SELECT * FROM `product` WHERE MATCH(`meta_desc`, `meta_keywords`) AGAINST('*ful*' IN BOOLEAN MODE) |
Данный запрос аналогичен результату при использовании LIKE ="%ful%", только использует значительно меньше ресурсов благодаря системе индексов MySQL
Искать не точное соответствие по введенной фразе и соответствие по ее частям можно таким образом:
1 2 3 4 5 | SELECT * FROM `product` WHERE MATCH(`meta_desc`, `meta_keywords`) AGAINST('*ful**nam*' IN BOOLEAN MODE) |
При таком запросе в результат попадут записи имеющие вхождения фрагментов слов ful и nam
Надо учесть, что при работе с MATCH запрещено использовать в качестве именно полей зарезервированные слова.
Существует список запрещенных к использованию слов, то есть следующими словами нельзя называть поля таблиц, чтобы потом использовать их в полнотекстовом поиске MySql:
| a’s | able | about | above | according |
| accordingly | across | actually | after | afterwards |
| again | against | ain’t | all | allow |
| allows | almost | alone | along | already |
| also | although | always | am | among |
| amongst | an | and | another | any |
| anybody | anyhow | anyone | anything | anyway |
| anyways | anywhere | apart | appear | appreciate |
| appropriate | are | aren’t | around | as |
| aside | ask | asking | associated | at |
| available | away | awfully | be | became |
| because | become | becomes | becoming | been |
| before | beforehand | behind | being | believe |
| below | beside | besides | best | better |
| between | beyond | both | brief | but |
| by | c’mon | c’s | came | can |
| can’t | cannot | cant | cause | causes |
| certain | certainly | changes | clearly | co |
| com | come | comes | concerning | consequently |
| consider | considering | contain | containing | contains |
| corresponding | could | couldn’t | course | currently |
| definitely | described | despite | did | didn’t |
| different | do | does | doesn’t | doing |
| don’t | done | down | downwards | during |
| each | edu | eg | eight | either |
| else | elsewhere | enough | entirely | especially |
| et | etc | even | ever | every |
| everybody | everyone | everything | everywhere | ex |
| exactly | example | except | far | few |
| fifth | first | five | followed | following |
| follows | for | former | formerly | forth |
| four | from | further | furthermore | get |
| gets | getting | given | gives | go |
| goes | going | gone | got | gotten |
| greetings | had | hadn’t | happens | hardly |
| has | hasn’t | have | haven’t | having |
| he | he’s | hello | help | hence |
| her | here | here’s | hereafter | hereby |
| herein | hereupon | hers | herself | hi |
| him | himself | his | hither | hopefully |
| how | howbeit | however | i’d | i’ll |
| i’m | i’ve | ie | if | ignored |
| immediate | in | inasmuch | inc | indeed |
| indicate | indicated | indicates | inner | insofar |
| instead | into | inward | is | isn’t |
| it | it’d | it’ll | it’s | its |
| itself | just | keep | keeps | kept |
| know | known | knows | last | lately |
| later | latter | latterly | least | less |
| lest | let | let’s | like | liked |
| likely | little | look | looking | looks |
| ltd | mainly | many | may | maybe |
| me | mean | meanwhile | merely | might |
| more | moreover | most | mostly | much |
| must | my | myself | name | namely |
| nd | near | nearly | necessary | need |
| needs | neither | never | nevertheless | new |
| next | nine | no | nobody | non |
| none | noone | nor | normally | not |
| nothing | novel | now | nowhere | obviously |
| of | off | often | oh | ok |
| okay | old | on | once | one |
| ones | only | onto | or | other |
| others | otherwise | ought | our | ours |
| ourselves | out | outside | over | overall |
| own | particular | particularly | per | perhaps |
| placed | please | plus | possible | presumably |
| probably | provides | que | quite | qv |
| rather | rd | re | really | reasonably |
| regarding | regardless | regards | relatively | respectively |
| right | said | same | saw | say |
| saying | says | second | secondly | see |
| seeing | seem | seemed | seeming | seems |
| seen | self | selves | sensible | sent |
| serious | seriously | seven | several | shall |
| she | should | shouldn’t | since | six |
| so | some | somebody | somehow | someone |
| something | sometime | sometimes | somewhat | somewhere |
| soon | sorry | specified | specify | specifying |
| still | sub | such | sup | sure |
| t’s | take | taken | tell | tends |
| th | than | thank | thanks | thanx |
| that | that’s | thats | the | their |
| theirs | them | themselves | then | thence |
| there | there’s | thereafter | thereby | therefore |
| therein | theres | thereupon | these | they |
| they’d | they’ll | they’re | they’ve | think |
| third | this | thorough | thoroughly | those |
| though | three | through | throughout | thru |
| thus | to | together | too | took |
| toward | towards | tried | tries | truly |
| try | trying | twice | two | un |
| under | unfortunately | unless | unlikely | until |
| unto | up | upon | us | use |
| used | useful | uses | using | usually |
| value | various | very | via | viz |
| vs | want | wants | was | wasn’t |
| way | we | we’d | we’ll | we’re |
| we’ve | welcome | well | went | were |
| weren’t | what | what’s | whatever | when |
| whence | whenever | where | where’s | whereafter |
| whereas | whereby | wherein | whereupon | wherever |
| whether | which | while | whither | who |
| who’s | whoever | whole | whom | whose |
| why | will | willing | wish | with |
| within | without | won’t | wonder | would |
| wouldn’t | yes | yet | you | you’d |
| you’ll | you’re | you’ve | your | yours |
| yourself | yourselves | zero |
Надо сказать, я потратил не один час на то чтобы понять, почему мой полнотекстовый поиск MySql то работает, то не очень, а ведь все дело оказалось именно в совпадении наименований полей с зарезервированными словами.
Как я и обещал, в начале статьи, задача реализации полнотекстового поиска в MySQL сводится к минимуму действий:
- Создание индекса для полей занятых в поиске.
- Выполнение sql запроса.
Возникли вопросы? Пишите в комментариях! Подписывайтесь на RSS рассылку, впереди много интересных и полезных статей.
Читайте также похожие статьи:
Чтобы не пропустить публикацию следующей статьи подписывайтесь на рассылку по E-mail или RSS ленту блога.


Комментарии
Упустил из виду то, что движок надо изменить на MyISAM. Поиск с помощью LIKE или REGEXP очень плохо, в FULLTEXT используется MATCH. Статья неплохая, но надо было дополнить про операторы такие как дефис, плюс и тд.
А так очень неплохо, спасибо за статью.
Да, про MyISAM действительно забыл упомянуть.
А вот про операторы дефис и плюс,
я к сожалению ничего не знаю, если вы поделитесь знаниями
об этих операторах, буду признателен.
Ну смотрите, примеры которые вы привели вообще то не очень правильные…
Например это
AGAINST(‘*ful**nam*’ IN BOOLEAN MODE
Оператор звездочка он ставится в конец, и является оператором усечения, то есть поиск будет происходить так:
— nam, name, names и тд.
Остальные операторы:
1) Дефис — Этот оператор указывает, что данное ключевое слово не должно содержаться в поле (NOT);
2) Плюс указывает, что слово должно обязательно содержаться в запросе (AND);
3) Ковычки — предполагается, что будут слова искаться целиком.
Это не окончательный список, это все что я помню.
Кстати есть еще Boolean MODE, вы его используете, а ведь можно его и не использовать, результаты будут разные….
Начал создавать индекс таблицы, нажимаю Структура и вижу, что у меня среди типов нет FULLTEXT. Начинается с VARCHAR, TINYINT и так далее, а нужного нет. Использую МАМР.
И еще, у меня таблица отличается от вашей: сперва идет #, потом Имя, затем Тип, Сравнение, Атрибуты и тд. Может, не там смотрю?
Перепутал. Не могу найти DESCTEXT!
VARCHAR, TINYINT и тп. это типы полей, а FULLTEXT — индекс таблицы. DESCTEXT — это произвольное название индекса.
Куда вписывать эти FULLTEXT и DESCTEXT? Захожу в таблицу products (там у меня все, что относится к товарам: id, title, description и тд). Жму добавить 1 поле, появляется окно Добавить столбцы. В нем Имя, Тип, Длина/значения и тд. Хотелось бы узнать.
Огромное спасибо за статью. Люблю когда автор, пишет все максимально просто и понятно. Сколько я в интернете прочел подобных статей, но до конца понял как работает полнотекстовый поиск, только прочев эту именно статью. 🙂
Рад, что оказалась полезной.
Большое спасибо, было очень полезно. Нашол то что искал, только в комментах… 😉 Но за статью тоже Respect, потому что …
Все отлично, но один вопрос:
есть запрос:
SELECT *, (SELECT txtName FROM tblObjects WHERE id=req.ObjectId) as obj,(SELECT txtAddress FROM tblObjects WHERE id=req.ObjectId) as adrs,(SELECT txtName FROM tblTexts WHERE id=req.StatusId) as status FROM tblRequests as req WHERE
добавляем:
AND MATCH(`txtBug`, `txtChange`, `txtComments`, `id`) AGAINST(‘*».$_REQUEST[‘find’].»*’ IN BOOLEAN MODE)
В итоге все работает,
но когда пытаюсь добавить поля такие как adrs,status — не находит ничего, помогите плиз что можно сделать?
adrs,status возьмите в кавычки — тильды.
А REGEXP что-то упустили в описании..:))
И тот кто пишет такое пытается тырить статьи, а сам понимаешь что пишешь?
Оператор LIKE
Оператор REGEXP
Операторы AGAINST и MATCH
Первые два оператора самый примитивный вариант для поиска по сайту, и кроме того очень медлительный и требующий большой производительности сервера.
А операторы AGAINST и MATCH ты хоть знаешь систему их работы, что чушь тут пишешь?
Надо сказать, я потратил не один час на то чтобы понять, почему мой полнотекстовый поиск MySql то работает, то не очень, а ведь все дело оказалось именно в совпадении наименований полей с зарезервированными словами.
Ну и как работают супер быстрые операторы AGAINST и MATCH???)))))