No MySQL, o
MATCH()
função executa uma pesquisa de texto completo. Ele aceita uma lista separada por vírgulas de colunas de tabela a serem pesquisadas. A(s) tabela(s) deve(m) ter um
FULLTEXT
index antes que você possa fazer uma pesquisa de texto completo neles (embora as consultas booleanas em um MyISAM
o índice de pesquisa pode funcionar - embora lentamente - mesmo sem um FULLTEXT
índice). Você pode criar um
FULLTEXT
index ao criar a tabela (usando o CREATE TABLE
instrução), ou você pode usar o ALTER TABLE
instrução ou o CREATE INDEX
declaração se a tabela já existir. Por padrão, a pesquisa não diferencia maiúsculas de minúsculas. Para realizar uma pesquisa com distinção entre maiúsculas e minúsculas, use uma ordenação binária ou com distinção entre maiúsculas e minúsculas para as colunas indexadas.
Sintaxe
A sintaxe para o
MATCH()
função fica assim:MATCH (col1,col2,...) AGAINST (expr [search_modifier])
Onde
col1,col2,...
é a lista de colunas separadas por vírgulas para pesquisar e expr
é a string/expressão de entrada. O
search_modifier
opcional O argumento permite especificar o tipo de pesquisa. Pode ser qualquer um dos seguintes valores:IN NATURAL LANGUAGE MODE
IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION
IN BOOLEAN MODE
WITH QUERY EXPANSION
O modo padrão é
IN NATURAL LANGUAGE MODE
. Exemplo 1 – Uso básico
Veja um exemplo de como usar esta função:
SELECT AlbumId, AlbumName FROM Albums WHERE MATCH(AlbumName) AGAINST('cool');
Resultado:
+---------+--------------------+ | AlbumId | AlbumName | +---------+--------------------+ | 5 | Casualties of Cool | +---------+--------------------+
Aqui está a tabela completa em que a consulta acima foi executada:
SELECT AlbumId, AlbumName FROM Albums;
Resultado:
+---------+--------------------------+ | AlbumId | AlbumName | +---------+--------------------------+ | 1 | Powerslave | | 2 | Powerage | | 3 | Singing Down the Lane | | 4 | Ziltoid the Omniscient | | 5 | Casualties of Cool | | 6 | Epicloud | | 7 | Somewhere in Time | | 8 | Piece of Mind | | 9 | Killers | | 10 | No Prayer for the Dying | | 11 | No Sound Without Silence | | 12 | Big Swing Face | | 13 | Blue Night | | 14 | Eternity | | 15 | Scandinavia | | 16 | Long Lost Suitcase | | 17 | Praise and Blame | | 18 | Along Came Jones | | 19 | All Night Wrong | | 20 | The Sixteen Men of Tain | +---------+--------------------------+
Exemplo 2 – Erro:“Não é possível encontrar o índice FULLTEXT”
InnoDB
as tabelas devem ter um FULLTEXT
index antes de retornar resultados de uma pesquisa de texto completo. Se não tiver um FULLTEXT
index, você provavelmente receberá o seguinte erro:ERROR 1191 (HY000): Can't find FULLTEXT index matching the column list
Se você receber esse erro, precisará adicionar um
FULLTEXT
index para todas as colunas que você está tentando pesquisar (veja o próximo exemplo). A exceção a isso pode ser se você estiver executando uma consulta booleana em um
MyISAM
índice de pesquisa. Para ser mais específico, a documentação do MySQL para pesquisas de texto completo booleanas afirma o seguinte:
InnoDB
as tabelas requerem umFULLTEXT
índice em todas as colunas doMATCH()
expressão para realizar consultas booleanas. Consultas booleanas em umMyISAM
o índice de pesquisa pode funcionar mesmo sem umFULLTEXT
index, embora uma busca executada desta forma seja bastante lenta.
Exemplo 3 – Adicionando um índice FULLTEXT a uma tabela existente
Aqui está um exemplo de como adicionar um
FULLTEXT
index para uma tabela existente:ALTER TABLE Albums ADD FULLTEXT(AlbumName);
Nesse caso, indexei o conteúdo do
AlbumName
coluna. Para indexar várias colunas, separe-as com uma vírgula (veja o próximo exemplo).
Exemplo 4 – Pesquisando várias colunas
Se você acha que precisará pesquisar mais de uma coluna, precisará criar um índice que inclua todas as colunas a serem pesquisadas. Para fazer isso, basta incluir cada coluna como uma lista separada por vírgulas.
Aqui está um exemplo onde eu adiciono um
FULLTEXT
índice para o film
table (que faz parte do banco de dados de exemplo Sakila). ALTER TABLE film ADD FULLTEXT(title, description);
Neste caso, eu indexo o conteúdo do
title
e description
colunas. Agora que criamos um
FULLTEXT
index para ambas as colunas, podemos fazer uma pesquisa de texto completo nelas:SELECT title, description FROM film WHERE MATCH(title, description) AGAINST('vertigo');
Resultado:
+-------------------+-----------------------------------------------------------------------------------------------------------+ | title | description | +-------------------+-----------------------------------------------------------------------------------------------------------+ | VERTIGO NORTHWEST | A Unbelieveable Display of a Mad Scientist And a Mad Scientist who must Outgun a Mad Cow in Ancient Japan | +-------------------+-----------------------------------------------------------------------------------------------------------+
Aqui está outra pesquisa, onde a frase-chave exata não corresponde, mas cada palavra-chave dentro dessa frase corresponde:
SELECT title, description FROM film WHERE MATCH(title, description) AGAINST('Iron Maiden');
Resultado:
+-------------+---------------------------------------------------------------------------------------------------------+ | title | description | +-------------+---------------------------------------------------------------------------------------------------------+ | IRON MOON | A Fast-Paced Documentary of a Mad Cow And a Boy who must Pursue a Dentist in A Baloon | | MAIDEN HOME | A Lacklusture Saga of a Moose And a Teacher who must Kill a Forensic Psychologist in A MySQL Convention | +-------------+---------------------------------------------------------------------------------------------------------+
Se você quiser apenas que a frase exata corresponda, coloque aspas duplas em torno dela:
SELECT title, description FROM film WHERE MATCH(title, description) AGAINST('"Iron Maiden"');
Resultado:
Empty set (0.00 sec)
Nesse caso, nenhuma das colunas contém essa frase exata.
Exemplo 5 – Retornar a pontuação de relevância
Sempre que você usar o
MATCH()
função, cada linha na tabela recebe um valor de relevância. Em outras palavras, cada linha recebe uma pontuação que determina o quão relevante é para o termo de pesquisa. Os resultados são então ordenados por relevância (maior relevância primeiro). Os valores de relevância são números de ponto flutuante não negativos. Relevância zero significa ausência de similaridade. A relevância é calculada com base no número de palavras na linha (documento), no número de palavras exclusivas na linha, no número total de palavras na coleção e no número de linhas que contêm uma palavra específica.
Para retornar a relevância de cada resultado, basta incluir o
MATCH()
função em sua lista de colunas para selecionar. Exemplo:
SELECT MATCH(title, description) AGAINST('Iron Maiden') AS Relevance, title, description FROM film WHERE MATCH(title, description) AGAINST('Iron Maiden');
Resultado:
+-----------+-------------+---------------------------------------------------------------------------------------------------------+ | Relevance | title | description | +-----------+-------------+---------------------------------------------------------------------------------------------------------+ | 9 | IRON MOON | A Fast-Paced Documentary of a Mad Cow And a Boy who must Pursue a Dentist in A Baloon | | 9 | MAIDEN HOME | A Lacklusture Saga of a Moose And a Teacher who must Kill a Forensic Psychologist in A MySQL Convention | +-----------+-------------+---------------------------------------------------------------------------------------------------------+
Nesse caso, a pontuação de relevância é muito alta para ambas as linhas.
Aqui está outro onde a relevância é menor:
SELECT MATCH(title, description) AGAINST('Saga of a Moose') AS Relevance, title, description FROM film WHERE MATCH(title, description) AGAINST('Saga of a Moose') LIMIT 15;
Resultado:
+--------------------+------------------------+---------------------------------------------------------------------------------------------------------+ | Relevance | title | description | +--------------------+------------------------+---------------------------------------------------------------------------------------------------------+ | 2.4431142807006836 | CAPER MOTIONS | A Fateful Saga of a Moose And a Car who must Pursue a Woman in A MySQL Convention | | 2.4431142807006836 | DATE SPEED | A Touching Saga of a Composer And a Moose who must Discover a Dentist in A MySQL Convention | | 2.4431142807006836 | DELIVERANCE MULHOLLAND | A Astounding Saga of a Monkey And a Moose who must Conquer a Butler in A Shark Tank | | 2.4431142807006836 | FLASH WARS | A Astounding Saga of a Moose And a Pastry Chef who must Chase a Student in The Gulf of Mexico | | 2.4431142807006836 | HAROLD FRENCH | A Stunning Saga of a Sumo Wrestler And a Student who must Outrace a Moose in The Sahara Desert | | 2.4431142807006836 | MAIDEN HOME | A Lacklusture Saga of a Moose And a Teacher who must Kill a Forensic Psychologist in A MySQL Convention | | 2.4431142807006836 | SHANE DARKNESS | A Action-Packed Saga of a Moose And a Lumberjack who must Find a Woman in Berlin | | 2.4431142807006836 | SLEEPLESS MONSOON | A Amazing Saga of a Moose And a Pastry Chef who must Escape a Butler in Australia | | 2.4431142807006836 | WAKE JAWS | A Beautiful Saga of a Feminist And a Composer who must Challenge a Moose in Berlin | | 2.4431142807006836 | WONKA SEA | A Brilliant Saga of a Boat And a Mad Scientist who must Meet a Moose in Ancient India | | 1.2399028539657593 | AIRPLANE SIERRA | A Touching Saga of a Hunter And a Butler who must Discover a Butler in A Jet Boat | | 1.2399028539657593 | ALASKA PHANTOM | A Fanciful Saga of a Hunter And a Pastry Chef who must Vanquish a Boy in Australia | | 1.2399028539657593 | ARMY FLINTSTONES | A Boring Saga of a Database Administrator And a Womanizer who must Battle a Waitress in Nigeria | | 1.2399028539657593 | BEAR GRACELAND | A Astounding Saga of a Dog And a Boy who must Kill a Teacher in The First Manned Space Station | | 1.2399028539657593 | BERETS AGENT | A Taut Saga of a Crocodile And a Boy who must Overcome a Technical Writer in Ancient China | +--------------------+------------------------+---------------------------------------------------------------------------------------------------------+
Observe que o conjunto de resultados teria sido muito maior se eu não tivesse usado
LIMIT 15
limitar o número de resultados a 15. Exemplo 6 - Retornar apenas resultados acima de uma certa pontuação de relevância
Podemos levar o exemplo anterior um passo adiante e filtrar apenas os resultados com uma determinada pontuação de relevância. Nesse caso, especifico que a pontuação de relevância deve ser maior que 2.
Tenha cuidado ao fazer isso embora. Como visto acima, os valores de relevância podem ser muito altos ou muito baixos, dependendo de fatores como a quantidade de texto na coluna, quantas outras linhas correspondem ao termo de pesquisa etc.
SELECT MATCH(title, description) AGAINST('Saga of a Moose') AS Relevance, title, description FROM film WHERE MATCH(title, description) AGAINST('Saga of a Moose') > 2;
Resultado:
+--------------------+------------------------+---------------------------------------------------------------------------------------------------------+ | Relevance | title | description | +--------------------+------------------------+---------------------------------------------------------------------------------------------------------+ | 2.4431142807006836 | CAPER MOTIONS | A Fateful Saga of a Moose And a Car who must Pursue a Woman in A MySQL Convention | | 2.4431142807006836 | DATE SPEED | A Touching Saga of a Composer And a Moose who must Discover a Dentist in A MySQL Convention | | 2.4431142807006836 | DELIVERANCE MULHOLLAND | A Astounding Saga of a Monkey And a Moose who must Conquer a Butler in A Shark Tank | | 2.4431142807006836 | FLASH WARS | A Astounding Saga of a Moose And a Pastry Chef who must Chase a Student in The Gulf of Mexico | | 2.4431142807006836 | HAROLD FRENCH | A Stunning Saga of a Sumo Wrestler And a Student who must Outrace a Moose in The Sahara Desert | | 2.4431142807006836 | MAIDEN HOME | A Lacklusture Saga of a Moose And a Teacher who must Kill a Forensic Psychologist in A MySQL Convention | | 2.4431142807006836 | SHANE DARKNESS | A Action-Packed Saga of a Moose And a Lumberjack who must Find a Woman in Berlin | | 2.4431142807006836 | SLEEPLESS MONSOON | A Amazing Saga of a Moose And a Pastry Chef who must Escape a Butler in Australia | | 2.4431142807006836 | WAKE JAWS | A Beautiful Saga of a Feminist And a Composer who must Challenge a Moose in Berlin | | 2.4431142807006836 | WONKA SEA | A Brilliant Saga of a Boat And a Mad Scientist who must Meet a Moose in Ancient India | +--------------------+------------------------+---------------------------------------------------------------------------------------------------------+
Exemplo 7 - Incluir resultados de relevância zero
Aqui está um exemplo de listagem dos valores de relevância para cada linha, mesmo que o valor de relevância seja zero. Podemos fazer isso não usando o
MATCH()
função no WHERE
cláusula. Neste exemplo, eu realmente não uso um
WHERE
cláusula. Eu uso apenas um LIMIT
cláusula para limitar o número de resultados. SELECT MATCH(title, description) AGAINST('Scientist') AS Relevance, title, description FROM film LIMIT 15;
Resultado:
+-------------------+------------------+-----------------------------------------------------------------------------------------------------------------------+ | Relevance | title | description | +-------------------+------------------+-----------------------------------------------------------------------------------------------------------------------+ | 1.026631474494934 | ACADEMY DINOSAUR | A Epic Drama of a Feminist And a Mad Scientist who must Battle a Teacher in The Canadian Rockies | | 0 | ACE GOLDFINGER | A Astounding Epistle of a Database Administrator And a Explorer who must Find a Car in Ancient China | | 0 | ADAPTATION HOLES | A Astounding Reflection of a Lumberjack And a Car who must Sink a Lumberjack in A Baloon Factory | | 0 | AFFAIR PREJUDICE | A Fanciful Documentary of a Frisbee And a Lumberjack who must Chase a Monkey in A Shark Tank | | 0 | AFRICAN EGG | A Fast-Paced Documentary of a Pastry Chef And a Dentist who must Pursue a Forensic Psychologist in The Gulf of Mexico | | 0 | AGENT TRUMAN | A Intrepid Panorama of a Robot And a Boy who must Escape a Sumo Wrestler in Ancient China | | 0 | AIRPLANE SIERRA | A Touching Saga of a Hunter And a Butler who must Discover a Butler in A Jet Boat | | 0 | AIRPORT POLLOCK | A Epic Tale of a Moose And a Girl who must Confront a Monkey in Ancient India | | 2.053262948989868 | ALABAMA DEVIL | A Thoughtful Panorama of a Database Administrator And a Mad Scientist who must Outgun a Mad Scientist in A Jet Boat | | 0 | ALADDIN CALENDAR | A Action-Packed Tale of a Man And a Lumberjack who must Reach a Feminist in Ancient China | | 0 | ALAMO VIDEOTAPE | A Boring Epistle of a Butler And a Cat who must Fight a Pastry Chef in A MySQL Convention | | 0 | ALASKA PHANTOM | A Fanciful Saga of a Hunter And a Pastry Chef who must Vanquish a Boy in Australia | | 0 | ALI FOREVER | A Action-Packed Drama of a Dentist And a Crocodile who must Battle a Feminist in The Canadian Rockies | | 0 | ALICE FANTASIA | A Emotional Drama of a A Shark And a Database Administrator who must Vanquish a Pioneer in Soviet Georgia | | 1.026631474494934 | ALIEN CENTER | A Brilliant Drama of a Cat And a Mad Scientist who must Battle a Feminist in A MySQL Convention | +-------------------+------------------+-----------------------------------------------------------------------------------------------------------------------+
Exemplo 8 – Modo booleano
O MySQL nos permite executar pesquisas de texto completo no modo booleano. Para fazer isso, adicione o
IN BOOLEAN MODE
modificador para sua consulta. O modo booleano permite que você use operadores como
+
e -
para especificar se uma determinada palavra ou frase deve ou não estar presente. No exemplo a seguir, prefixo cada palavra com um sinal de mais (
+
) para indicar que ambas as palavras devem estar presentes. SELECT title, description FROM film WHERE MATCH(title, description) AGAINST('+Saga +Moose' IN BOOLEAN MODE) LIMIT 3;
Resultado:
+------------------------+---------------------------------------------------------------------------------------------+ | title | description | +------------------------+---------------------------------------------------------------------------------------------+ | CAPER MOTIONS | A Fateful Saga of a Moose And a Car who must Pursue a Woman in A MySQL Convention | | DATE SPEED | A Touching Saga of a Composer And a Moose who must Discover a Dentist in A MySQL Convention | | DELIVERANCE MULHOLLAND | A Astounding Saga of a Monkey And a Moose who must Conquer a Butler in A Shark Tank | +------------------------+---------------------------------------------------------------------------------------------+
No próximo exemplo, altero um dos sinais de mais para um sinal de menos (
-
). Isso significa que apenas as linhas que contêm a palavra Saga
serão devolvidos, mas somente se não também contém Moose
:SELECT title, description FROM film WHERE MATCH(title, description) AGAINST('+Saga -Moose' IN BOOLEAN MODE) LIMIT 3;
Resultado:
+------------------+-------------------------------------------------------------------------------------------------+ | title | description | +------------------+-------------------------------------------------------------------------------------------------+ | AIRPLANE SIERRA | A Touching Saga of a Hunter And a Butler who must Discover a Butler in A Jet Boat | | ALASKA PHANTOM | A Fanciful Saga of a Hunter And a Pastry Chef who must Vanquish a Boy in Australia | | ARMY FLINTSTONES | A Boring Saga of a Database Administrator And a Womanizer who must Battle a Waitress in Nigeria | +------------------+-------------------------------------------------------------------------------------------------+
O sinal de menos é usado para excluir resultados que de outra forma seriam retornados. Portanto, se todas as nossas palavras de pesquisa forem prefixadas com um sinal de menos, um conjunto vazio será retornado.
SELECT title, description FROM film WHERE MATCH(title, description) AGAINST('-Saga -Moose' IN BOOLEAN MODE) LIMIT 3;
Resultado:
Empty set (0.00 sec)
Existem muitos outros operadores que podem ser usados com pesquisas booleanas, como
~
, <
, >
, *
, e mais. Para obter informações mais detalhadas sobre como usar o modo booleano, consulte a documentação do MySQL para pesquisas de texto completo booleano. Exemplo 9 – Com expansão de consulta cega
Você pode usar o
WITH QUERY EXPANSION
ou o IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION
modificadores para realizar a expansão de consulta cega. Isso pode ser útil quando a frase de pesquisa é muito curta e onde os resultados retornados podem ser muito limitados (excluindo, assim, documentos potencialmente relevantes). A expansão da consulta pode ampliar a pesquisa retornando linhas que de outra forma não seriam retornadas. Em particular, se uma linha não correspondente contiver palavras que também estão contidas em uma linha correspondente, essa linha não correspondente poderá se tornar uma linha correspondente. Em outras palavras, uma linha não correspondente ainda pode ser retornada, simplesmente porque ela compartilha outras palavras com uma linha correspondente.
Para demonstrar, aqui está uma pesquisa normal sem expansão da consulta:
SELECT AlbumId, AlbumName FROM Albums WHERE MATCH(AlbumName) AGAINST('Blue' IN NATURAL LANGUAGE MODE);
Resultado:
+---------+------------+ | AlbumId | AlbumName | +---------+------------+ | 13 | Blue Night | +---------+------------+
Eu declarei explicitamente
IN NATURAL LANGUAGE MODE
mas este é o modo padrão, então eu também poderia ter omitido este modificador se assim o quisesse. E aqui está a mesma pesquisa com expansão da consulta:
SELECT AlbumId, AlbumName FROM Albums WHERE MATCH(AlbumName) AGAINST('Blue' WITH QUERY EXPANSION);
Resultado:
+---------+-----------------+ | AlbumId | AlbumName | +---------+-----------------+ | 13 | Blue Night | | 19 | All Night Wrong | +---------+-----------------+
Nesse caso, dois resultados são retornados. Observe como o segundo resultado não contém a frase de pesquisa (
blue
). Mas contém a palavra Night
que também está no primeiro resultado. Portanto, a consulta expandida considera isso bom o suficiente para ser uma correspondência. Os nomes dos álbuns provavelmente não são um bom caso de uso para o modo de expansão de consulta. Um caso de uso melhor pode ser uma pesquisa por, digamos, banco de dados , onde uma consulta expandida também pode retornar documentos que contenham nomes como MySQL , Oráculo , etc, mesmo que não contenham a frase banco de dados .
Aqui está outro exemplo. No entanto, este exemplo usa aspas duplas para especificar que todo o termo de pesquisa deve estar presente.
Se fizermos a pesquisa sem expansão da consulta:
SELECT title, description FROM film WHERE MATCH(title, description) AGAINST('"Feminist And a Mad Scientist"') LIMIT 3;
Resultado:
+------------------+--------------------------------------------------------------------------------------------------+ | title | description | +------------------+--------------------------------------------------------------------------------------------------+ | ACADEMY DINOSAUR | A Epic Drama of a Feminist And a Mad Scientist who must Battle a Teacher in The Canadian Rockies | +------------------+--------------------------------------------------------------------------------------------------+
Apenas um resultado é retornado (é o único resultado que contém a frase inteira, exatamente como digitada).
Mas se usarmos a expansão de consulta cega, eis o que acontece:
SELECT title, description FROM film WHERE MATCH(title, description) AGAINST('"Feminist And a Mad Scientist"' WITH QUERY EXPANSION) LIMIT 3;
Resultado:
+--------------------+------------------------------------------------------------------------------------------------------+ | title | description | +--------------------+------------------------------------------------------------------------------------------------------+ | ACADEMY DINOSAUR | A Epic Drama of a Feminist And a Mad Scientist who must Battle a Teacher in The Canadian Rockies | | DINOSAUR SECRETARY | A Action-Packed Drama of a Feminist And a Girl who must Reach a Robot in The Canadian Rockies | | VICTORY ACADEMY | A Insightful Epistle of a Mad Scientist And a Explorer who must Challenge a Cat in The Sahara Desert | +--------------------+------------------------------------------------------------------------------------------------------+
A primeira linha é a mesma de quando não usamos a expansão de consulta. No entanto, a consulta retorna e retorna linhas que contêm apenas partes do nosso termo de pesquisa. Este resultado está limitado a três apenas porque usei
LIMIT 3
. Os resultados reais são muito maiores:SELECT COUNT(*) FROM film WHERE MATCH(title, description) AGAINST('"Feminist And a Mad Scientist"' WITH QUERY EXPANSION);
Resultado:
+----------+ | COUNT(*) | +----------+ | 1000 | +----------+
É bem possível que muitos desses resultados sejam completamente irrelevantes para o termo de pesquisa. Portanto, a expansão de consulta cega geralmente funciona melhor para termos de pesquisa mais curtos.
Para obter mais informações sobre como usar a expansão de consulta cega, consulte a documentação do MySQL:Pesquisas de texto completo com expansão de consulta.