2011-07-15 12 views
6

Sto lavorando a una funzione di ricerca in una delle mie app basate sui dati principali e sto cercando di raccogliere tutti i suggerimenti sull'ottimizzazione della ricerca per ottenerla il più velocemente possibile. La ricerca deve essere abbastanza veloce da fornire risultati quasi istantanei per un database di oltre 20.000 oggetti.Ottimizzazione della ricerca dei dati principali

Quello che ho fatto finora (per quanto riguarda l'ottimizzazione va)

  • implementato la tecnica mostrata nella WWDC 2010 sessione di 137, la creazione di un'entità parola chiave e la creazione di un rapporto a-molti dei miei principali entità oggetto ad esso. L'attributo dell'entità parola chiave name è indicizzato, e le parole chiave vengono creati durante la procedura iniziale di importazione, dividendo le stringhe a parte rilevanti nei soggetti principali e normalizzare (spogliato di cassa e segni diacritici)
  • Utilizzando >= e < comparatori binari invece di BEGINSWITH, ecc . il mio formato predicato è:

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

Dove $LB è la stringa limiti inferiore e $UB è limiti superiori. Creo un predicato composto AND utilizzando questo formato e l'array di termini di ricerca.

In questo momento, sto eseguendo un'operazione di recupero una volta (quando l'utente digita la prima lettera) utilizzando una dimensione di recupero lotto di circa 20, e quindi restringendo i risultati di ricerca utilizzando il metodo di -filteredArrayUsingPredicate NSArray mentre continuano a digitare. Predispongo anche alla relazione keywords perché viene utilizzata per filtrare. La parte che occupa più tempo, ovviamente, è il recupero iniziale. C'è un notevole ritardo di ~ 1-2 secondi su una libreria di circa 15.000 oggetti. profiling tempo dimostra che è in effetti l'operazione di recupero che sta causando il ritardo:

http://cl.ly/3a1b2022452M2V323f2H

Un altra cosa questo è degni di nota è che devo andare a prendere più entità per i risultati. Tutte le entità hanno un attributo ranking, ma non riesco a recuperarne più di una in una volta, quindi sono costretto a recuperarle separatamente, combinarle in un unico array e quindi ordinare manualmente tramite -sortedArrayUsingDescriptors.

Tutti i suggerimenti su come accelerare questo sarebbe molto apprezzato.

EDIT: Sulla base di suggerimenti @ImHuntingWabbits':

Dopo l'aggiunta di un'entità KeywordFirstChar, il mio modello di dati (semplificato) sarebbe simile a questa:

new model

Ora, le domande è come scrivere un predicato per l'entità Car basata su KeywordFirstChar? L'unica cosa che mi viene in mente sarebbe questo:

SUBQUERY(keywords, $keyword, $keyword.firstChar.char == %@) dove %@ è il carattere da cercare, ma non so come questo sarebbe molto più efficace se si considera che ha ancora enumerare oltre keywords, a meno che non erroneamente interpretato i suggerimenti.

+0

Non stai iterando su ogni parola chiave, l'SQL generato dovrebbe solo controllare il valore del char nella tabella keywordFirstChar. Il set di risultati delle entità Car verrà recuperato eseguendo un join da KeywordFirstChar a Keyword per Car. – ImHuntingWabbits

+0

Sì, capito. Funziona molto meglio ora, molto più velocemente. Grazie – indragie

risposta

4

La tua query è altamente ottimizzata, penso che tu abbia già preso un buon numero di passaggi.Per quanto riguarda la stampa del primo personaggio, ti stai sbagliando.

Stai ancora eseguendo la scansione di 15k record per il primo hit del personaggio, e probabilmente corrisponde a un gran numero di essi.

Si potrebbe ulteriormente ottimizzarlo per l'indicizzazione del tuo indice delle parole chiave, la creazione di due nuove entità:

  • KeywordFirstChar
  • KeywordFirstTwoChars

Entrambi con un rapporto a-molti per le parole chiave a cui puntano .

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

In questo modo, la scansione della tabella andrà oltre le 26 e 676 righe rispettivamente, il che dovrebbe essere piuttosto banale. Assicurati solo che la relazione sia nei percorsi delle chiavi di relazione prefetched nella richiesta di recupero in modo da ottenere effettivamente i dati dal disco.

Edit (Object Retrieval):

È possibile seguire il percorso della chiave rapporto, quindi sarebbe qualcosa di simile:

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

Dove parola chiave è il rapporto all'entità delle parole chiave, e SourceObject è l'oggetto che si desidera recuperare.

Edit (Predicate):

Il predicato è essenzialmente lo stesso, basta cambiare i nomi in modo che corrisponda alla nuova entità (nome potrebbe non mappare nome, invece PrimoCar o qualche altra proprietà).

+0

Grazie per la risposta, questa soluzione ha molto senso. Detto questo, non sono completamente sicuro dei dettagli. Ad esempio, che aspetto avrebbe il mio predicato per il recupero dell'entità "KeywordFirstChar" e come recuperare i miei oggetti principali (quelli che sono collegati alle parole chiave) da tale recupero? – indragie

+0

Ho modificato il mio post per includere più dettagli (in base ai tuoi suggerimenti aggiuntivi) perché penso che potrei interpretare male qualcosa, – indragie

Problemi correlati