2011-07-15 8 views
6

Estoy trabajando en una función de búsqueda en una de mis aplicaciones basadas en datos centrales y estoy tratando de reunir los consejos de todos sobre la optimización de búsqueda para obtenerla lo más rápido posible. La búsqueda debe ser lo suficientemente rápida como para proporcionar resultados casi instantáneos para la base de datos de más de 20,000 objetos.Optimización de búsqueda de datos principales

Lo que he hecho hasta ahora (en lo que va de optimización)

  • implementó la técnica mostrada en la WWDC 2010 Sesión 137, la creación de una entidad de palabras clave y crear una relación a muchos de mis principales entidades de objetos lo. atributo de la entidad palabra clave name está indexado, y las palabras clave son creados durante el procedimiento inicial de importación mediante el fraccionamiento de cadenas separadas relevantes en las entidades principales y la normalización de ellos (despojado de caso y signos diacríticos)
  • Usando >= y < comparadores binarios en lugar de BEGINSWITH etc . Mi formato predicado es:

SUBQUERY(keywords, $keyword, ($keyword.name >= $LB) AND ($keyword.name < $UB))[email protected] != 0

Dónde $LB es la cadena de límites inferior y es $UB límites superiores. Creo un predicado compuesto AND usando este formato y la matriz de términos de búsqueda.

En este momento estoy ejecutando una búsqueda (cuando el usuario escribe la primera letra) utilizando un tamaño de lote de búsqueda de aproximadamente 20, y luego reduciendo los resultados de búsqueda utilizando el método NSArray -filteredArrayUsingPredicate mientras continúan escribiendo. También prefetch la relación keywords porque esto se usa para filtrar. La parte que ocupa más tiempo, obviamente, es la búsqueda inicial. Hay una notable demora de ~ 1-2s en una biblioteca de alrededor de 15,000 objetos. perfiles de tiempo muestra que es de hecho la zona de alcance que está causando el retraso:

http://cl.ly/3a1b2022452M2V323f2H

otro eso es cosa que cabe destacar es que tengo que ir a buscar múltiples entidades de los resultados. Todas las entidades tienen un atributo ranking, pero no puedo buscar más de una a la vez, así que me veo obligado a buscarlas por separado, combinarlas en una única matriz y luego ordenarlas manualmente a través del -sortedArrayUsingDescriptors.

Cualquier consejo sobre cómo acelerar esto sería muy apreciado.

EDIT: Sobre la base de las sugerencias @ImHuntingWabbits':

Después de agregar una entidad KeywordFirstChar, mi modelo de datos (simplificado) podría tener este aspecto:

new model

Ahora, la pregunta es ¿cómo escribiría un predicado para la entidad Car que recupera según KeywordFirstChar? Lo único que se me ocurre sería la siguiente:

SUBQUERY(keywords, $keyword, $keyword.firstChar.char == %@) donde %@ es el carácter a buscar, pero no saben cómo esto sería mucho más eficiente teniendo en cuenta que todavía tiene que enumerar más de keywords, a menos que yo malinterpretó las sugerencias.

+0

No está iterando sobre cada palabra clave, el SQL generado solo debería verificar el valor char en la tabla keywordFirstChar. El conjunto de resultados de las entidades de Auto se buscará haciendo una combinación desde KeywordFirstChar a Keyword to Car. – ImHuntingWabbits

+0

Sí, lo tengo. Funciona mucho mejor ahora, mucho más rápido. Gracias – indragie

Respuesta

4

Su consulta está muy optimizada, creo que ya ha dado un buen número de pasos.En cuanto a la primera pulsación de personaje, lo estás haciendo mal.

Todavía está escaneando 15k registros para el primer golpe de personaje, y probablemente coincida con un gran número de ellos.

Se puede optimizar aún más por la indexación de su índice de palabras clave, la creación de dos nuevas entidades:

  • KeywordFirstChar
  • KeywordFirstTwoChars

ambos con una relación de muchos a las palabras clave que apuntan .

if (searchPredicate.length == 1) { 
    //search on KeywordFirstChar 
} else if (searchPredicate.length == 2) { 
    //search on KeywordFirstTwoChars 
} else { 
    //search on keyword 
} 

De esta manera su recorrido de tabla repasará máximo de 26 y 676 filas, respectivamente, que debe ser bastante trivial. Solo asegúrate de que la relación esté en las rutas clave de relación de captación previa en la solicitud de recuperación, de modo que de hecho saques los datos del disco.

Editar (Object Recuperación):

se puede seguir la ruta de la clave relación, por lo que sería algo como esto:

[fetchRequest setRelationshipKeyPathsForPrefetching:[NSArray arrayWithObject:@"keyword.sourceObject"]]; 

Donde palabra clave es la relación de la entidad de palabras clave, y SourceObject es el objeto que desea recuperar finalmente.

Editar (predicado):

El predicado es esencialmente el mismo, solo cambia los nombres para que coincida con la nueva entidad (nombre podría no asignar al nombre, en lugar aPartirDe o alguna otra propiedad).

+0

Gracias por la respuesta, esa solución tiene mucho sentido. Dicho esto, no estoy completamente seguro de los detalles. Por ejemplo, ¿cómo se vería mi predicado buscando la entidad "KeywordFirstChar" y cómo recuperaría mis objetos principales (los que están conectados a las palabras clave) de esa búsqueda? – indragie

+0

He editado mi publicación para incluir más detalles (en función de sus sugerencias adicionales) porque creo que podría estar malinterpretando algo, – indragie

Cuestiones relacionadas