Actualmente estoy usando Datomic en uno de mis proyectos, y una pregunta me está molestando.

Aquí hay una versión simplificada de mi problema:

  • Necesito analizar una lista de pequeñas oraciones en inglés e insertar tanto la oración completa como sus palabras en Datomic.
  • el archivo que contiene la lista de oraciones es bastante grande (> 10 GB)
  • la misma oración puede aparecer varias veces en el archivo y sus palabras también pueden aparecer varias veces en las oraciones
  • durante el proceso de inserción, se establecerá un atributo para asociar cada oración con sus palabras correspondientes

Para facilitar el proceso de inserción, tengo la tentación de escribir los mismos datos varias veces (es decir, no verificar si ya existe un registro en la base de datos). Pero me da miedo el impacto en el rendimiento.

  • ¿Qué sucede en Datomic cuando se agregan los mismos datoms varias veces?
  • ¿Vale la pena comprobar que ya se ha agregado un datom antes de la transacción?

  • ¿Hay alguna manera de evitar que Datomic anule datos anteriores (es decir, si ya existe un registro, omita la transacción)?

Gracias por su ayuda

2
user5239066 23 dic. 2016 a las 19:47

3 respuestas

La mejor respuesta
  • ¿Qué sucede en Datomic cuando se agregan los mismos datoms varias veces?
  • ¿Vale la pena comprobar que ya se ha agregado un datom antes de la transacción?

Lógicamente, una base de datos Datomic es un conjunto ordenado de datoms, por lo que agregar el mismo datom varias veces es idempotente. Sin embargo, cuando está afirmando un datom con un tempid, puede crear un nuevo datom para representar la misma información que un datom antiguo. Aquí es donde :db/unique entra.

Para asegurarse de que una entidad no se almacene varias veces, desea establecer la propiedad de atributo :db/unique en :db.unique/identity para los atributos correctos. Por ejemplo, si su esquema consta de 3 atributos :word/text, :sentence/text y :sentence/words, entonces :word/text y :sentence/text deberían ser :db.unique/identity, que produce la siguiente transacción de instalación de esquema:

[{:db/cardinality :db.cardinality/one,
  :db/fulltext true,
  :db/index true,
  :db.install/_attribute :db.part/db,
  :db/id #db/id[:db.part/db -1000777],
  :db/ident :sentence/text,
  :db/valueType :db.type/string,
  :db/unique :db.unique/identity}
 {:db/cardinality :db.cardinality/one,
  :db/fulltext true,
  :db/index true,
  :db.install/_attribute :db.part/db,
  :db/id #db/id[:db.part/db -1000778],
  :db/ident :word/text,
  :db/valueType :db.type/string,
  :db/unique :db.unique/identity}
 {:db/cardinality :db.cardinality/many,
  :db/fulltext true,
  :db/index true,
  :db.install/_attribute :db.part/db,
  :db/id #db/id[:db.part/db -1000779],
  :db/ident :sentence/words,
  :db/valueType :db.type/ref}]

Entonces la transacción para insertar insertar se ve así:

[{:sentence/text "Hello World!"
  :sentence/words [{:word/text "hello"
                    :db/id (d/tempid :db.part/user)}
                   {:word/text "world"
                    :db/id (d/tempid :db.part/user)}]
  :db/id (d/tempid :db.part/user)}]

En cuanto al rendimiento:

Es posible que no necesite optimizar en absoluto, pero en mi opinión, los posibles cuellos de botella de rendimiento de su proceso de importación son:

  1. tiempo dedicado a construir la transacción en el Transactor (que incluye búsquedas de índice para atributos únicos, etc.)
  2. tiempo dedicado a construir los índices.

Para mejorar 2.: Cuando se ordenan los datos que inserta, la indexación es más rápida, por lo que sería insertar palabras y oraciones ordenadas. Puede usar las herramientas de Unix para ordenar archivos grandes incluso si no caben en la memoria. Entonces el proceso sería:

  • ordenar oraciones, insertarlas (:sentence/text)
  • extraer palabras, ordenarlas, insertarlas (:word/text)
  • insertar relación palabra-oración (:sentence/words)

Para mejorar 1.: de hecho, podría ejercer menos presión sobre el operador para usar identificadores de entidad para las palabras que ya están almacenadas en lugar del texto completo de la palabra (que requiere una búsqueda de índice para garantizar la unicidad). Una idea podría ser realizar esa búsqueda en el par, ya sea aprovechando el paralelismo y / o solo para palabras frecuentes (por ejemplo, podría insertar las palabras de las primeras 1000 oraciones, luego recuperar sus identificadores de entidad y mantenerlos en un mapa hash )

Personalmente, no pasaría por estas optimizaciones hasta que la experiencia haya demostrado que son necesarias.

2
Valentin Waeselynck 26 dic. 2016 a las 21:41

No está en el punto en que debe preocuparse por la optimización previa como esta. Las tiendas minoristas de computadoras venden discos duros por alrededor de $ 0.05 / GB, por lo que está hablando de 50 centavos de almacenamiento aquí. Con la compresión de almacenamiento incorporada de Datomic, esto será aún más pequeño. Los índices y otros gastos generales aumentarán un poco el total, pero aún es demasiado pequeño para preocuparse.

Como con cualquier problema, es mejor construir una solución de forma incremental. Entonces, tal vez haga un experimento con el primer 1% de sus datos y cronometre el algoritmo más simple posible. Si eso es bastante rápido, prueba 10%. Ahora tiene una estimación bastante buena de cuánto tiempo tomará cargar todo el problema. Apuesto a que consultar los datos será aún más rápido que cargar.

Si se encuentra con un obstáculo después del primer 1% o 10%, entonces puede pensar en reelaborar el diseño. Como ha construido algo concreto, se ha visto obligado a pensar en el problema y la solución con más detalle. Esto es mucho mejor que los argumentos que agitan a mano y el diseño de pizarra. Ahora sabe mucho más sobre sus datos y posibles implementaciones de soluciones.

Si resulta que la solución más simple no funcionará a mayor escala, la segunda solución será mucho más fácil de diseñar e implementar habiendo tenido la experiencia de la primera solución. Muy raramente, la solución final surge completamente de su mente. Es muy importante para cualquier problema significativo planificar un refinamiento repetido de la solución.

Uno de mis capítulos favoritos del libro seminal. El Mes del Hombre Mítico de Fred Brooks se titula, " Plan para tirar uno ".

1
Alan Thompson 23 dic. 2016 a las 18:35
  • ¿Qué sucede en Datomic cuando se agregan los mismos datoms varias veces?

Si está agregando la palabra / oración con una identidad única (: db.unique / identity), Datomic mantendrá solo una copia en el almacenamiento (es decir, una sola entidad)

  • ¿Vale la pena comprobar que ya se ha agregado un datom antes de la transacción?
  • ¿Hay alguna manera de evitar que Datomic anule datos anteriores (es decir, si ya existe un registro, omita la transacción)? *

Nuevamente, use: db.unique / identity, entonces no necesita consultar la identificación de la entidad para verificar su existencia.

Para obtener más información, consulte aquí

1
rmcv 24 dic. 2016 a las 04:15