2011-02-14 19 views
5

He serializado una lista de objetos con protobuf-net.Filtrado masivo con protobuf-net

Teóricamente, el archivo .bin puede contener millones de objetos.

Supongamos que los objetos son de una clase que contenga lo siguiente:

public string EventName; 

tengo que tomar una consulta y crear una lista que contiene los objetos que coincidan con la consulta. ¿Cuál es la forma correcta de extraer los objetos coincidentes del archivo serializado utilizando LINQ?

Respuesta

5

El formato protobuf es una secuencia lineal de elementos; cualquier indización, etc., solo se puede aplicar por separado. Sin embargo, IEnumerable<T> está disponible; puede encontrar que:

var item = Serializer.DeserializeItems<YourType>(source) 
     .First(item => item.Id == id); 

hace el trabajo muy bien; esto:

  • es lazyily spooled; cada elemento se entrega de forma individual, por lo que no necesita un exceso de memoria
  • está en cortocircuito; Si el artículo se encuentra cerca de la salida, que va a salir rápidamente

O por varios elementos:

var list = Serializer.DeserializeItems<YourType>(source) 
    .Where(item => item.Foo == foo); 

(Añadir un ToList que te final de la anterior si desea amortiguar los elementos coincidentes en memoria, o usar sin ToList si solo quieres analizarlo de una sola vez)

+0

Creo que esta solución es buena, pero el código debería poder extraer una cantidad de objetos que coincidan con la consulta. –

+0

@Gilad: ¿has visto mi actualización con '.Where()'? –

+0

Muchas gracias, Mark :). De nuevo. ¿Qué debería pasar como argumento para "etiqueta" en los métodos de DeserializeItems? –

0

Lamentablemente, no hay ninguna. Para usar LINQ, su objeto debe implementar IQueryable<T> o IEnumerable<T>. A menos que haya un proveedor de LINQ que puede proporcionar una interfaz IQueryable<T> en su archivo .bin, ya sea que usted tiene que:

  • deserializar el archivo en memoria y utilizar LINQ a objetos IEnumerable<T>
  • Escribe tu LINQ proveedor que puede proporcionar un IQueryable<T> (y esta es probablemente la única opción práctica si su archivo es ENORME) que puede procesar el archivo sin cargarlo todo.
+0

Un buen trabajo que DeserializeItems proporciona una API 'IEnumerable ', luego –

+0

@Marc: ¡Parece que sí! Supuse que la deserialización cargaría todo el archivo en la memoria. Evidentemente estaba equivocado en eso. –

+0

se enrollará holgadamente ('yield return') de la transmisión - ideal para procesar grandes volúmenes de datos –

0

protobuf puede darle el contenido de los archivos como una transmisión IEnumerable<T>, por lo que puede hacerlo fácilmente. Lamentablemente, no sé cómo se llama el método, pero es fácil de encontrar en los documentos.

+0

DeserializeItems –

+0

@Marc ¿cómo debo serializar elementos para usar DeserializeItems? ¿Tienes un ejemplo rápido en cualquier lugar?Estoy atrapado tratando de hacer esto en V2. – gjvdkamp

+0

No importa, fue en el PrefixStyle.Base128 – gjvdkamp

1

Si quieres agregar alguna proyección sobre la lista de elementos seleccionada, deberías probar una biblioteca mía, https://github.com/Scooletz/protobuf-linq. Están disponibles en NuGet también. La biblioteca reduce en gran medida la sobrecarga de la deserialización. En algunos casos, puede caer al 50% de la consulta original.