Cette fois, j'ai utilisé Apache Arrow pour étudier l'échange de données entre Java et python.
On s'attend à ce que l'échange de données à l'aide d'Apache Arrow puisse être copié entre les systèmes et les langues sans copie en mémoire. Pour écrire la conclusion en premier, dans cette recherche, elle a été échangée via un tableau d'octets au format Apache Arrow. Vous n'êtes pas obligé de l'écrire sur votre disque local, mais la sérialisation Java et la désérialisation python entraîneront une copie des données en mémoire. Je pense que l'avantage de la méthode introduite cette fois-ci est qu'il est facile de faire le lien entre les langues car il existe un format commun à haute vitesse appelé Apache Arrow.
Apache Arrow avait une bibliothèque appelée jvm pour échanger des données entre Java et python. Cette bibliothèque implémente une fonction qui, si vous passez un objet Java Apache Arrow VectorSchemaRoot, le convertira en un RecordBatch python.
def record_batch(jvm_vector_schema_root):
"""
Construct a (Python) RecordBatch from a JVM VectorSchemaRoot
Parameters
----------
jvm_vector_schema_root : org.apache.arrow.vector.VectorSchemaRoot
Returns
-------
record_batch: pyarrow.RecordBatch
"""
Par conséquent, on suppose que l'échange de données entre Java et python peut être facilement effectué en utilisant py4j.
Obtenez les pots dont vous avez besoin pour utiliser py4j. Le pom suivant apporte la flèche et les bocaux py4j localement.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>gtest</groupId>
<artifactId>gtest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>gtest</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.arrow</groupId>
<artifactId>arrow-vector</artifactId>
<version>0.12.0</version>
</dependency>
<dependency>
<groupId>net.sf.py4j</groupId>
<artifactId>py4j</artifactId>
<version>0.10.8.1</version>
</dependency>
</dependencies>
</project>
La commande maven est la suivante.
$ mvn dependency:copy-dependencies -DoutputDirectory=./lib -f ./pom.xml
Créez une classe Java simple en vous référant à l'exemple py4j. Il implémente également une fonction qui renvoie VecotrSchemaRoot pour validation sur py4j.
import java.util.List;
import java.util.ArrayList;
import py4j.GatewayServer;
import org.apache.arrow.memory.RootAllocator;
import org.apache.arrow.vector.BitVector;
import org.apache.arrow.vector.VectorSchemaRoot;
public class Py4jExample {
public static void main( final String[] args ) {
Py4jExample app = new Py4jExample();
GatewayServer server = new GatewayServer( app );
server.start();
}
/**
*Préparez une fonction pour créer un VectorSchemaRoot à essayer.
*/
public static VectorSchemaRoot create() {
RootAllocator allocator = new RootAllocator( Integer.MAX_VALUE );
BitVector vector = new BitVector( "test" , allocator );
vector.allocateNew( 1 );
vector.setSafe( 0 , 1 );
vector.setValueCount( 1 );
List list = new ArrayList();
list.add( vector );
VectorSchemaRoot root = new VectorSchemaRoot( list );
root.setRowCount( 1 );
return root;
}
}
Compilez et démarrez.
$ javac -cp lib/*:. Py4jExample.java
$ java -cp lib/*:. Py4jExample &
Maintenant que nous sommes prêts à appeler depuis python, écrivons le processus python.
from py4j.java_gateway import JavaGateway
import pyarrow as pa
import pyarrow.jvm as j
from pyarrow import RecordBatch
gateway = JavaGateway()
root = gateway.jvm.Py4jExample.create()
rb = j.record_batch( root )
df = rb.to_pandas()
J'ai pensé qu'il serait facile de convertir de java en record_batch de python en utilisant la bibliothèque jvm comme celle-ci ...
$ python test.py
Segmentation fault
Vous pouvez l'exécuter jusqu'au point où vous obtenez RecordBatch, mais il semble se bloquer lorsque vous appelez to_pandas (). Je ne peux pas dire si mon environnement était mauvais, mais je ne semblais pas le comprendre tout de suite, alors j'ai décidé d'abandonner cette fois.
Alternativement, Apache Arrow implémente également un format binaire pour le fichier, afin qu'il puisse être lu et écrit par Java et python dans un tableau d'octets. En regardant l'implémentation actuelle (en mars 2019) de python jvm, il semblait être copié en mémoire lors de la réception d'un objet Java et de sa conversion en objet python. Par conséquent, l'échange de données avec des tableaux d'octets nécessite une sérialisation et une désérialisation, mais seule la sérialisation vers des tableaux d'octets en Java est coûteuse.
Ajoutez une fonction à la classe Java qui crée un tableau d'octets.
/**
*Préparez une fonction pour créer un tableau d'octets de Arrow à essayer.
*/
public static byte[] createArrowFile() throws IOException {
RootAllocator allocator = new RootAllocator( Integer.MAX_VALUE );
BitVector vector = new BitVector( "test" , allocator );
vector.allocateNew( 1 );
vector.setSafe( 0 , 1 );
vector.setValueCount( 1 );
List list = new ArrayList();
list.add( vector );
VectorSchemaRoot root = new VectorSchemaRoot( list );
root.setRowCount( 1 );
ByteArrayOutputStream out = new ByteArrayOutputStream();
ArrowFileWriter writer = new ArrowFileWriter( root, null, Channels.newChannel( out ) );
writer.start();
writer.writeBatch();
writer.end();
writer.close();
return out.toByteArray();
}
Compilez cette classe et redémarrez-la. Le traitement en python est modifié pour obtenir RecordBatch à partir du tableau d'octets.
from py4j.java_gateway import JavaGateway
import pyarrow as pa
import pyarrow.jvm as j
from pyarrow import RecordBatch
gateway = JavaGateway()
reader = pa.RecordBatchFileReader( pa.BufferReader( gateway.jvm.Py4jExample.createArrowFile() ) )
rb = reader.get_record_batch(0);
df = rb.to_pandas()
print df
Comme prévu, le résultat de cette exécution était que VectorSchemaRoot créé en Java pouvait être traité comme RecordBatch en python.
$ python test2.py
test
0 True
L'échange de données entre Java et python est maintenant devenu une implémentation de force brute. Cependant, Apache Arrow présente l'avantage d'être compatible avec les bibliothèques qui traitent les données avec python telles que les pandas, et que vous n'avez pas à implémenter votre propre sérialisation et désérialisation.
Le but de cette recherche était de rendre le format de fichier que nous développons actuellement implémenté en Java et également disponible en python, qui est couramment utilisé dans le traitement des données. La prochaine fois, sur la base de cette recherche, j'aimerais écrire un exemple d'implémentation et de fonctionnement de la lecture et de l'écriture de python dans un format de fichier avec un tableau d'octets.
Recommended Posts