Menu Docs
Página inicial do Docs
/ / /
PyMongoArrow

Comparação com o PyMongo

Nesta página

  • Lendo dados
  • Escrevendo dados
  • Referências

Neste guia, você aprenderá sobre as diferenças entre o PyMongoArrow e o driver do PyMongo. Este guia pressupõe familiaridade com conceitos básicos de PyMongo e MongoDB .

A maneira mais básica de ler dados usando o PyMongo é:

coll = db.benchmark
f = list(coll.find({}, projection={"_id": 0}))
table = pyarrow.Table.from_pylist(f)

Isso funciona, mas você precisa excluir o campo _id , caso contrário, você receberá o seguinte erro:

pyarrow.lib.ArrowInvalid: Could not convert ObjectId('642f2f4720d92a85355671b3') with type ObjectId: did not recognize Python value type when inferring an Arrow data type

O exemplo de código a seguir mostra uma solução alternativa para o erro anterior ao usar o 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

Mesmo que isso evite o erro, uma desvantagem é que o Arrow não consegue identificar que _id é um ObjectId, conforme observado pelo esquema que mostra _id como uma string.

O PyMongoArrow suporta BSON types por meio dos tipos de extensão Arrow ou Pandas. Isso permite que você evite a solução 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

Com esse método, a Arrow identifica corretamente o tipo. Isso tem uso limitado para tipos de extensão não numéricas, mas evita a conversão desnecessária para determinadas operações, como classificar data/hora.

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()
)

Além disso, o PyMongoArrow oferece suporte aos tipos de extensão Pandas. Com o PyMongo, um valor Decimal128 se comporta da seguinte forma:

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

O equivalente no PyMongoArrow é:

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

Em ambos os casos, os valores subjacentes são o tipo de classe BSON:

print(df["value"][0])
Decimal128("0")

A gravação de dados de uma tabela Arrow usando o PyMongo parece com o seguinte:

data = arrow_table.to_pylist()
db.collname.insert_many(data)

O equivalente no PyMongoArrow é:

from pymongoarrow.api import write
write(db.collname, arrow_table)

A partir do PyMongoArrow 1.0, a principal vantagem de usar a função write é que ela itera sobre a tabela de setas, conjunto de dados ou matriz numpy e não converte o objeto inteiro em uma lista.

As seguintes medições foram feitas com o PyMongoArrow versão 1.0 e o PyMongo versão 4.4. Para inserções, a biblioteca tem quase o mesmo desempenho do que ao usar o PyMongo convencional e usa a mesma quantidade de memória.

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

Para leituras, a biblioteca é mais lenta para documentos pequenos e documentos aninhados, mas mais rápida para documentos grandes. Ele usa menos memória em todos os 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

Voltar

NOVIDADES