Actualmente estoy tratando de mejorar mi algoritmo de búsqueda.¿Cómo implemento una búsqueda tipo "fonética"
Para una mejor comprensión, aquí está la lógica actual detrás de ella:
tenemos objetos con n palabras clave adjuntas en db. en la base de datos esto se resuelve a través de 2 tablas (Object
, Keyword
) donde el Keyword
-table tiene un FK a Object
. Cuando estoy construyendo mis campos de búsqueda, creo un valor de línea (ad: quitar diéresis, convertir a minúsculas, ...) de todas las palabras clave de un objeto. la misma rutina de conversión (NormalizeSearchPattern()
) se realiza con los patrones de búsqueda. Estoy apoyando AND
-búsqueda y palabras clave con una longitud mínima de 2 caracteres solamente!
La búsqueda algoritmo es actualmente una variante de fast-reverse-search
(este ejemplo no está optimizado):
bool IsMatch(string source, string searchPattern)
{
// example:
// source: "hello world"
// searchPattern: "hello you freaky funky world"
// patterns[]: { "hello", "you", "freaky", "funky", "world" }
searchPattern = NormalizeSearchPattern(searchPattern);
var patterns = MagicMethodToSplitPatternIntoPatterns(searchPattern);
foreach (var pattern in patterns)
{
var success = false;
var patternLength = pattern.Length;
var firstChar = pattern[0];
var secondChar = pattern[1];
var lengthDifference = input.Length - patternLength;
while (lengthDifference >= 0)
{
if (source[lengthDifference--] != firstChar)
{
continue;
}
if (source[lengthDifference + 2] != secondChar)
{
continue;
}
var l = lengthDifference + 3;
var m = 2;
while (m < patternLength)
{
if (input[l] != pattern[m])
{
break;
}
l++;
m++;
}
if (m == patternLength)
{
success = true;
}
}
if (!success)
{
return false;
}
}
return true;
}
La normalización se realiza con (este ejemplo no está optimizado)
string RemoveTooShortKeywords(string keywords)
{
while (Regex.IsMatch(keywords, TooShortKeywordPattern, RegexOptions.Compiled | RegexOptions.Singleline))
{
keywords = Regex.Replace(keywords, TooShortKeywordPattern, " ", RegexOptions.Compiled | RegexOptions.Singleline);
}
return keywords;
}
string RemoveNonAlphaDigits(string value)
{
value = value.ToLower();
value = value.Replace("ä", "ae");
value = value.Replace("ö", "oe");
value = value.Replace("ü", "ue");
value = value.Replace("ß", "ss");
return Regex.Replace(value, "[^a-z 0-9]", " ", RegexOptions.Compiled | RegexOptions.Singleline);
}
string NormalizeSearchPattern(string searchPattern)
{
var resultNonAlphaDigits = RemoveNonAlphaDigits(searchPattern);
var resultTrimmed = RemoveTooShortKeywords(resultNonAlphaDigits);
return resultTrimmed;
}
Así que esto es bastante sencillo, por lo tanto, es obvio que solo puedo lidiar con las variantes de source
y searchPattern
que he implementado en NormalizeSearchPattern()
(como se mencionó anteriormente: diéresis, diferencias de mayúsculas y minúsculas, ...).
Pero, ¿cómo debería mejorar el algoritmo (o NormalizeSearchPattern()
) para ser no sensible cuando se trata de:
- singular/plural
- misstyping (por ejemplo, "hauserr" < -> "Hauser. ")
- ...
Sólo para saber más sobre el diseño:
Esta aplicación se hace en C#, que almacena la búsqueda árboles y objetos en una variable estática (para consultar la base de datos solo una vez en init), el rendimiento debe ser sobresaliente (actualmente se consultan 500.000 valores de línea en menos de 300 ms).
podría por favor elaborar mi código de demostración? –
Necesitará un diccionario para hacer coincidir. Escanear la wikipedia para obtener un primer borrador del diccionario es suficiente. Luego, divide todas estas palabras en bi (2) o tri (3) gramos. 'Hello' será:' hel', 'ell',' llo'. Al hacer coincidir una palabra, divídelo también, por lo que 'Helllo' será:' Hel', 'ell',' lll' y 'llo'. Ahora calcule estas coincidencias y ordénelas por relevancia. 'Helllo' coincidirá con' Hello', pero también podría coincidir con otras palabras. – Arcturus
También vea: http://en.wikipedia.org/wiki/N-gram – Arcturus