Conclusión
Problema cerrado, creo.
Parece que el problema no tuvo nada que ver con la metodología, pero que el XCode no limpió el proyecto correctamente entre compilaciones.
Parece que después de todas esas pruebas, el archivo sqlite que se estaba utilizando seguía siendo el primero que no se indexó ......
Tenga cuidado con XCode 4.3.2, no tengo más que problemas con Clean no limpiar, o la adición de archivos de proyecto no se añade automáticamente a los recursos de paquete ...
Gracias por las diferentes respuestas ..¿Cuál es la forma más rápida de cargar un gran archivo CSV en los datos centrales
Actualizar 3
Desde invito a cualquiera a sólo tratar los mismos pasos para ver si obtienen los mismos resultados, déjenme detallar lo que hice:
Comienzo con proyecto en blanco
que definen un modelo de datos con una sola entidad, 3 atributos (2 cadenas, 1 float)
La primera cadena está indexado
En qué finishLaunchingWithOptions, estoy llamando:
[self performSelectorInBackground:@selector(populateDB) withObject:nil];
El código para populateDb está abajo:
-(void)populateDB{
NSLog(@"start");
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
NSManagedObjectContext *context;
if (coordinator != nil) {
context = [[NSManagedObjectContext alloc] init];
[context setPersistentStoreCoordinator:coordinator];
}
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"input" ofType:@"txt"];
if (filePath) {
NSString * myText = [[NSString alloc]
initWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding
error:nil];
if (myText) {
__block int count = 0;
[myText enumerateLinesUsingBlock:^(NSString * line, BOOL * stop) {
line=[line stringByReplacingOccurrencesOfString:@"\t" withString:@" "];
NSArray *lineComponents=[line componentsSeparatedByString:@" "];
if(lineComponents){
if([lineComponents count]==3){
float f=[[lineComponents objectAtIndex:0] floatValue];
NSNumber *number=[NSNumber numberWithFloat:f];
NSString *string1=[lineComponents objectAtIndex:1];
NSString *string2=[lineComponents objectAtIndex:2];
NSManagedObject *object=[NSEntityDescription insertNewObjectForEntityForName:@"Bigram" inManagedObjectContext:context];
[object setValue:number forKey:@"number"];
[object setValue:string1 forKey:@"string1"];
[object setValue:string2 forKey:@"string2"];
NSError *error;
count++;
if(count>=1000){
if (![context save:&error]) {
NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
}
count=0;
}
}
}
}];
NSLog(@"done importing");
NSError *error;
if (![context save:&error]) {
NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
}
}
}
NSLog(@"end");
}
Todo lo demás es código de datos del núcleo por defecto, nada añadido.
Lo ejecuto en el simulador.
voy a ~/Library/Application Support/iPhone Simulator/5.1/Aplicaciones // Documentos
existe el archivo de SQLite que se genera
tomo eso y lo copio en mi paquete
Me comentario el llamado a populateDb
edito persistentStoreCoordinator para copiar el archivo de SQLite paquete de documentos a la primera carrera
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
@synchronized (self)
{
if (__persistentStoreCoordinator != nil)
return __persistentStoreCoordinator;
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:@"myProject" ofType:@"sqlite"];
NSString *storePath = [[[self applicationDocumentsDirectory] path] stringByAppendingPathComponent: @"myProject.sqlite"];
NSError *error;
if (![[NSFileManager defaultManager] fileExistsAtPath:storePath])
{
if ([[NSFileManager defaultManager] copyItemAtPath:defaultStorePath toPath:storePath error:&error])
NSLog(@"Copied starting data to %@", storePath);
else
NSLog(@"Error copying default DB to %@ (%@)", storePath, error);
}
NSURL *storeURL = [NSURL fileURLWithPath:storePath];
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return __persistentStoreCoordinator;
}
}
Elimino la aplicación del simulador, comprobé que ~/Library/Application Support/iPhone Simulator/5.1/Applications/ahora se eliminó
Reconstruyo y lance de nuevo
Como era de esperar, el archivo sqlite se copia en ~/Library/Application Support/iPhone Simulator/5.1/Aplicaciones // Documentos
Sin embargo, el tamaño del archivo es más pequeño que en el paquete, ¡significativamente! También, haciendo una consulta simple con un predicado como este predicado = [NSPredicate predicateWithFormat: @ "string1 ==% @", string1]; muestra claramente que cadena1 no está indexado más
Después de eso, se crea una nueva versión del modelo de datos, con una actualización sin sentido, sólo para forzar una migración de peso ligero
si se ejecuta en el simulador, la migración tiene unos pocos segundos, la base de datos se duplica en tamaño y la misma consulta ahora demora menos de un segundo en vez de minutos.
Esto resolvería mi problema, forzaría una migración, pero esa misma migración lleva 3 minutos en el iPad y ocurre en primer plano.
Así que, donde estoy en este momento, la mejor solución para mí sería evitar que los índices se eliminen, cualquier otra solución de importación en el momento del lanzamiento simplemente lleva demasiado tiempo.
Déjeme saber si usted necesita más aclaraciones ...
Actualización 2
lo tanto, el mejor resultado que he tenido hasta ahora es sembrar la base de datos central de datos con el archivo de SQLite producido a partir de una herramienta rápida con similares modelo de datos, pero sin los índices establecidos al producir el archivo sqlite. Luego, importo este archivo sqlite en la aplicación de datos central con los índices establecidos y permitiendo una migración ligera. Para grabar 2 millones en el nuevo iPad, esta migración toma 3 minutos. La aplicación final debe tener 5 veces este número de registros, por lo que todavía estamos buscando un largo tiempo de procesamiento. Si tomo esa ruta, la nueva pregunta sería: ¿se puede realizar una migración ligera en segundo plano?
actualización
mi pregunta no es cómo crear una herramienta para poblar una base de datos central de datos y, a continuación, importar el archivo de SQLite en mi aplicación.
Sé cómo hacer esto, lo he hecho en innumerables ocasiones.
Pero hasta ahora, no me había dado cuenta de que dicho método podría tener algún efecto secundario: en mi caso, un atributo indexado en la base de datos resultante claramente 'no indexado' al importar el archivo sqlite de esa manera.
Si pudo verificar que los datos indexados aún están indexados después de dicha transferencia, me interesa saber cómo procede o, de lo contrario, cuál sería la mejor estrategia para generar dicha base de datos de manera eficiente.
original
Tengo un archivo CSV grande (millones de líneas) con 4 columnas, cuerdas y flotadores. Esto es para una aplicación iOS.
Necesito que esto se cargue en los datos principales la primera vez que se carga la aplicación.
La aplicación no funciona mucho hasta que los datos están disponibles, por lo que el tiempo de carga es importante, ya que el usuario por primera vez obviamente no quiere que la aplicación tarde 20 minutos en cargarse antes de poder ejecutarla.
En este momento, mi código actual demora 20 minutos en el nuevo iPad para procesar un archivo csv de 2 millones de líneas.
estoy usando un contexto de fondo para no bloquear la interfaz de usuario, y guardar el contexto cada 1.000 registros
La primera idea que tuve fue generar la base de datos en el simulador, a continuación, copiar/pegar en la carpeta de documentos en primer lanzamiento, ya que esta es la forma común no oficial de sembrar una gran base de datos. Desafortunadamente, los índices no parecen sobrevivir a dicha transferencia, y aunque la base de datos estuvo disponible después de unos pocos segundos, el rendimiento es terrible porque mis índices se perdieron. Ya publiqué una pregunta sobre los índices, pero no parece haber una buena respuesta para eso.
Así que lo que estoy buscando, ya sea:
- una manera de mejorar el rendimiento en la carga de millones de registros de datos básicos
- si la base de datos está pre-cargado y se trasladó a primera puesta en marcha, de manera para mantener mis índices
- mejores prácticas para manejar este tipo de situaciones.No recuerdo haber usado ninguna aplicación que requiera que espere x minutos antes del primer uso (pero tal vez The Daily, y esa fue una experiencia terrible).
- Cualquier forma creativa de hacer que el usuario espere sin que él se dé cuenta: importación en segundo plano al pasar por el tutorial, etc ...
- ¿No está utilizando Core Data?
- ...
Entonces, ¿cómo terminaste "limpiando" el proyecto para que funcionara correctamente? – lnafziger
La limpieza no funcionó, pero el reinicio del equipo portátil, la limpieza manual de todas las referencias al archivo, etc., parece haber "resuelto" el problema. extraño ... aunque también tuve que quitar las líneas de migración livianas para forzarme a no migrar (ya que esto tomaría muchos minutos). En general, esta no es la implementación limpia que esperaría, pero esto funciona ... hasta que una versión 2 necesite una actualización de modelo de datos, entonces estoy en problemas –