En esta guía, aprenderá sobre las diferencias entre PyMongoArrow y el controlador de PyMongo. Esta guía presupone que está familiarizado con los conceptos básicos. Conceptos dePyMongo y MongoDB.
Lectura de datos
La forma más básica de leer datos usando PyMongo es:
coll = db.benchmark f = list(coll.find({}, projection={"_id": 0})) table = pyarrow.Table.from_pylist(f)
Esto funciona, pero hay que excluir el _id campo, de lo contrario obtendrá el siguiente error:
pyarrow.lib.ArrowInvalid: Could not convert ObjectId('642f2f4720d92a85355671b3') with type ObjectId: did not recognize Python value type when inferring an Arrow data type
El siguiente ejemplo de código muestra una solución alternativa para el error anterior al usar PyMongo:
f = list(coll.find({})) for doc in f: doc["_id"] = str(doc["_id"]) ... table = pyarrow.Table.from_pylist(f) print(table) pyarrow.Table _id: string x: int64 y: double
Si bien esto evita el error, una desventaja es que Arrow no puede identificar que _id es un ObjectId, como lo indica el esquema que muestra _id como una cadena.
PyMongoArrow admite tipos BSON mediante Arrow o los tipos de extensión de Pandas. Esto permite evitar la solución alternativa anterior.
from pymongoarrow.types import ObjectIdType schema = Schema({"_id": ObjectIdType(), "x": pyarrow.int64(), "y": pyarrow.float64()}) table = find_arrow_all(coll, {}, schema=schema) print(table) pyarrow.Table _id: extension<arrow.py_extension_type<ObjectIdType>> x: int64 y: double
Con este método, Arrow identifica correctamente el tipo. Su uso es limitado para tipos de extensión no numéricos, pero evita conversiones innecesarias para ciertas operaciones, como la ordenación de fechas y horas.
f = list(coll.find({}, projection={"_id": 0, "x": 0})) naive_table = pyarrow.Table.from_pylist(f) schema = Schema({"time": pyarrow.timestamp("ms")}) table = find_arrow_all(coll, {}, schema=schema) assert ( table.sort_by([("time", "ascending")])["time"] == naive_table["time"].cast(pyarrow.timestamp("ms")).sort() )
Además, PyMongoArrow admite los tipos de extensión de Pandas. Con PyMongo, un valor Decimal128 se comporta de la siguiente manera:
coll = client.test.test coll.insert_many([{"value": Decimal128(str(i))} for i in range(200)]) cursor = coll.find({}) df = pd.DataFrame(list(cursor)) print(df.dtypes) # _id object # value object
El equivalente en PyMongoArrow es:
from pymongoarrow.api import find_pandas_all coll = client.test.test coll.insert_many([{"value": Decimal128(str(i))} for i in range(200)]) df = find_pandas_all(coll, {}) print(df.dtypes) # _id bson_PandasObjectId # value bson_PandasDecimal128
En ambos casos, los valores subyacentes son el tipo de clase BSON:
print(df["value"][0]) Decimal128("0")
Escritura de datos
Escribir datos desde una tabla Arrow usando PyMongo se ve así:
data = arrow_table.to_pylist() db.collname.insert_many(data)
El equivalente en PyMongoArrow es:
from pymongoarrow.api import write write(db.collname, arrow_table)
A partir de PyMongoArrow 1.0, la principal ventaja de usar la función write es que itera sobre la tabla de flechas, el marco de datos o la matriz numpy, y no convierte el objeto completo en una lista.
Puntos de referencia
Las siguientes mediciones se realizaron con PyMongoArrow versión 1.0 y PyMongo versión 4.4. En cuanto a las inserciones, la biblioteca funciona prácticamente igual que con PyMongo convencional y utiliza la misma cantidad de memoria.
ProfileInsertSmall.peakmem_insert_conventional 107M ProfileInsertSmall.peakmem_insert_arrow 108M ProfileInsertSmall.time_insert_conventional 202±0.8ms ProfileInsertSmall.time_insert_arrow 181±0.4ms ProfileInsertLarge.peakmem_insert_arrow 127M ProfileInsertLarge.peakmem_insert_conventional 125M ProfileInsertLarge.time_insert_arrow 425±1ms ProfileInsertLarge.time_insert_conventional 440±1ms
En cuanto a las lecturas, la biblioteca es más lenta para documentos pequeños y anidados, pero más rápida para documentos grandes. Utiliza menos memoria en todos los casos.
ProfileReadSmall.peakmem_conventional_arrow 85.8M ProfileReadSmall.peakmem_to_arrow 83.1M ProfileReadSmall.time_conventional_arrow 38.1±0.3ms ProfileReadSmall.time_to_arrow 60.8±0.3ms ProfileReadLarge.peakmem_conventional_arrow 138M ProfileReadLarge.peakmem_to_arrow 106M ProfileReadLarge.time_conventional_ndarray 243±20ms ProfileReadLarge.time_to_arrow 186±0.8ms ProfileReadDocument.peakmem_conventional_arrow 209M ProfileReadDocument.peakmem_to_arrow 152M ProfileReadDocument.time_conventional_arrow 865±7ms ProfileReadDocument.time_to_arrow 937±1ms