Tengo una tabla con contenido de columna que tiene un índice FULLTEXT .
Quiero aprovechar la velocidad de MATCH() en texto grande.
Quiero que la búsqueda sea lo más precisa posible.
Cuando busco la cadena de frases " camión grande " de esta manera:
SELECT * FROM MyTable WHERE MATCH(content) AGAINST('"large truck"' IN BOOLEAN MODE);Se pierden algunos casos.
Mi mesa:
| content | ---------------- |Large \n truck| FOUND ✓ ---------------- |large truck | FOUND ✓ ---------------- |large trucks | *PLURAL MISSED! ---------------- |large truckl | *TYPE-O MISSED!Si uso el método estándar LIKE / wildcard :
SELECT * FROM `MyTable` WHERE `content` LIKE '%large truck%'Mi mesa:
| content | ---------------- |Large \n truck| *MISSED! ---------------- |large truck | FOUND ✓ ---------------- |large trucks | FOUND ✓ ---------------- |large truckl | FOUND ✓Parece que tampoco puedo usar una búsqueda de FRASES con comodines:
SELECT * FROM MyTable WHERE MATCH(content) AGAINST('"large truck*"' IN BOOLEAN MODE); **DOES NOT WORK**O
SELECT * FROM MyTable WHERE MATCH(content) AGAINST('"large truck"*' IN BOOLEAN MODE); **DOES NOT WORK**Asi que...
¿Cómo uso con éxito MATCH() AGAINST() buscando una frase y obtengo todas las instancias devueltas, incluso coincidencias de cadenas parciales que no distinguen entre mayúsculas y minúsculas?
El truco que suelo usar con FT es hacerlo en dos pasos:
MATCH , con la esperanza de obtener todo el texto deseado, pero posiblemente algunos resultados adicionales.AND con otra condición: LIKE (más rápido) o REGEXP (más potente). El MATCH será rápido gracias a FT; la otra parte se realizará en segundo lugar, por lo que será rápido porque no hay muchas filas para verificar.
Esto coincide con sus criterios:
SELECT * FROM MyTable WHERE MATCH(content) AGAINST('+large +truck*' IN BOOLEAN MODE) AND content REGEXP "large[[:space:]]+truck";Dicho de otra manera, la consulta se ejecutará de la siguiente manera:
MATCH será muy rápido (por la forma en que está diseñado). Encontrará todas las filas con "grande" y "camión*" en cualquier parte del content . Ahora, digamos, hay 30 filas que satisfacen eso.WHERE se evalúa. Pero se hace contra solo esas 30 filas. Entonces, aunque el REGEXP es costoso, no se realiza con frecuencia.El efecto neto es que toda la consulta se ejecuta "rápido", que era uno de sus requisitos.
Nota: necesitaba la segunda parte para evitar estos
large green truck the truck is large Dependiendo de la versión, es posible que necesite este REGEXP en su lugar: "large\\s+truck" .
Aquí hay un truco rápido con REGEXP, pero no está resolviendo el problema ya que no usa el índice de texto completo:
SELECT * FROM MyTable WHERE content REGEXP("large[[:space:]]+truck*");Por supuesto, también puede utilizar el índice FT buscando sin frase exacta:
SELECT * FROM MyTable WHERE MATCH(content) AGAINST('+large +truck*' IN BOOLEAN MODE);Pero esto eventualmente incluirá registros que no desea, ya que no es lo mismo que la búsqueda de frases exactas.
Desafortunadamente, la búsqueda de frases (comillas dobles - "") y el operador de truncamiento (comodín - *) no funcionarán independientemente de si usa InnoDB o MyISAM. Tampoco funciona con el operador de distancia con InnoDB (que probablemente provenga del mismo origen). Supongo que está relacionado con la naturaleza de cómo se almacenan los datos del índice de texto completo.