IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Format d'échange (XML, JSON...) Java Discussion :

XML trop gros en mémoire : un moyen d'alléger ?


Sujet :

Format d'échange (XML, JSON...) Java

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    90
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2007
    Messages : 90
    Par défaut XML trop gros en mémoire : un moyen d'alléger ?
    Bonjour à tous,

    J'ai une appli qui papote avec une base de données PostgreSQL via JDBC et qui fait plein de 'select' sur cette base pour construire un fichier xml récapitulatif. Tout est en contenu en mémoire puisque le fichier est uniquement constitué de balises imbriquées.
    J'appelle ensuite un XMLOutputter et je lui demande un prettyformat.


    Tout fonctionne très bien sur une base moyenne. Mais dès que la base est très grande, je passe d'un temps de quelques minutes à plusieurs heures ....

    Le processus le plus long est à mon avis se fait au niveau de tous les selects qui, à cause du principe récursif, conserve tout en mémoire et donc c'est extrêmement lourd à supporter pour la machine. Sans compter le XML qui une fois écrit fait plusieurs centaines de mega et donc en mémoire ne facilite pas le tout.

    Est ce que quelqu'un aurait une vague idée sur un moyen d'alléger le process


    Merci beaucoup,

  2. #2
    Modérateur
    Avatar de dinobogan
    Homme Profil pro
    ingénieur
    Inscrit en
    Juin 2007
    Messages
    4 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : ingénieur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 4 073
    Par défaut
    Citation Envoyé par rednik Voir le message
    Tout est en contenu en mémoire puisque le fichier est uniquement constitué de balises imbriquées.
    Il n'y a pas de cause à effet. Tu pourrais écrire ton fichier XML au fur et à mesure, sans le conserver en mémoire. Il faut simplement ajouter une pile dans laquelle tu conserves les balises ouvertes. A la fin de l'écriture du fichier, tu dépiles les balises de la pile et tu écris les balises fermantes correspondantes.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java
    Que la force de la puissance soit avec le courage de ta sagesse.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    90
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2007
    Messages : 90
    Par défaut
    Il est vrai que c'est ce qui semble le plus logique mais du coup on ne 'manipule' plus aucune donnée XML (Adieu prettyPrinter ), c'est à dire qu'on écrit dans un fichier de la même façon que n'importe quel autre avec une comptabilisation des espaces dans chaque recursion et tout ?

    C'est ça que tu voulais dire dinobogan ou j'ai mal compris ?

    Merci

  4. #4
    Modérateur
    Avatar de dinobogan
    Homme Profil pro
    ingénieur
    Inscrit en
    Juin 2007
    Messages
    4 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : ingénieur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 4 073
    Par défaut
    Citation Envoyé par rednik Voir le message
    C'est ça que tu voulais dire dinobogan où j'ai mal compris ?
    Oui, c'est exactement ça.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java
    Que la force de la puissance soit avec le courage de ta sagesse.

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    90
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2007
    Messages : 90
    Par défaut
    Bonjour à tous,

    Bon en fait ça ne change pas grand chose... Le fichier met toujours 6h à être généré (180Mo). J'ai cependant gagné une demi heure !

    Voici ma fonction principale de génération . Si quelqu'un a une idée sur une quelconque amélioration, je suis super preneuse !


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    	private static void writeTableXML(Table table, 
    			String whereRequest)
    	throws SQLException
    	{
    		// Execute Select Query on current table	
    		if (table == null)
    			return;
                    ResultSet row = executeQuery(table.buildCommand(whereRequest));
    		if (row == null || !row.next())
    			{
    				return;
    			}
    		do
    		{
    			// Write new line with name <tableName>
    			beforeWritingTable(table);
     
    			Iterator<Column> columnit = table.getIteratorOnColumns();
    			//Iterator on each column to add a new element 
    			while (columnit.hasNext())
    			{
    			   Column column = columnit.next();
    			    // If column name is a related table, recursive call
    			  if (column.isTable()
    			  {
    				for (Iterator<String> _itTable = column.getRelatedTable(); _itTable.hasNext() ; )
    		           writeTableXML(getRelatedTable(_itTable.next()), column.getCommand(row));	
    				}
    				// Column is only a value
    				else if (row != null)
    				{
    					String value = row.getString(column.getName());
    					if (value != null)
    					{		
    						writeElement(column.getName(), value);
    					}
    				}
    				// Column with no corresponding value is not written.
    				else if (row == null)
    				break;					
    			}
    			afterWritingTable(table.getName());
    		}
    		while (row != null && row.next());
    		if (row !=  null)
    			row.close();
    	}
    Merci,

  6. #6
    Modérateur
    Avatar de dinobogan
    Homme Profil pro
    ingénieur
    Inscrit en
    Juin 2007
    Messages
    4 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : ingénieur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 4 073
    Par défaut
    Il nous manque plein de chose pour t'aider par exemple qu'est-ce que l'objet Table, et aussi le code des diverses méthodes.
    Pour savoir ce qui prend le plus de temps, calcul le temps d'exécution des différentes parties de ton algo. Cherche d'où vient la contention.Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    long time = System.currenttimemillis();
    ...la partie à chronométrer...
    time = System.currenttimemillis() - time;
    System.out.println( "execution : " + time + " ms" );
    Puis tente différentes techniques pour récupérer les données en base puisque c'est manifestement là le soucis. Essais par exemple les PrepareStatement.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java
    Que la force de la puissance soit avec le courage de ta sagesse.

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    90
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2007
    Messages : 90
    Par défaut
    Pardon oui.

    Les fonctions d'écriture à chaque fois sont toutes simples. Du genre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    	public void beforeWritingTable(Table table) {
    		try {
    			_file.write("<" + table.getName());
    		} catch (IOException e) {
    			ErrorHandle.getInstance().handleIOException("XML Generator", "IO Error while writing the XML output file");
    		}
    	} 
    	public void afterWritingTable(String tablename) {
    		try {
    			_file.write("</" + tablename + ">\n");
    		} catch (IOException e) {
    			ErrorHandle.getInstance().handleIOException("XML Generator", "IO Error while writing the XML output file");
    		}
    	}
    sachant que _file est un FileWriter.


    Ensuite la class Table est juste une classe qui contient toutes les infos pour une table (de la database) donnée. Toutes les infos sont lues dans un XML d'entrée. Elle contient notamment la liste des champs, et la fin de la requête (where blablabla) à executer lors de l'accès à la base.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    	public String buildCommand(String whereRequest)
    	{
    		String cmd;
     
    		if ( whereRequest != null && whereRequest.length() != 0)
    		{
    			cmd = "SELECT " + _fields + " FROM GEN." + _name + " WHERE  " + whereRequest;
    			return cmd;
    		}
    		else
    			cmd = "SELECT " + _fields + " FROM GEN." + _name +  ";";
    		return cmd;	
    	}
    Sinon je viens de voir que la méthode executeQuery avait un problème. A chaque execution, je créais un Statement et oubliais de le refermer.... Ce qui vu le nombre de requêtes devait aider à ralentir considérablement le bazar. C'est corrigé maintenant.

    Je relance et je vous tiens au courant

    Merci dinobogan en tous cas !

  8. #8
    Modérateur
    Avatar de dinobogan
    Homme Profil pro
    ingénieur
    Inscrit en
    Juin 2007
    Messages
    4 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : ingénieur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 4 073
    Par défaut
    Pour les méthodes "beforeWritingTable" et "afterWritingTable", il ne faut pas faire de try/catch à l'intérieur. Fait un essai sans le catch, et déplace-le à l'extérieur de ta boucle while. Je pense que le gain de temps ne sera pas négligeable. Mais il faut pour cela supprimer ta récursivité : cela diminuera aussi le nombre d'instances des différents objets.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java
    Que la force de la puissance soit avec le courage de ta sagesse.

  9. #9
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    90
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2007
    Messages : 90
    Par défaut
    Rebonjour,

    Alors plusieurs problèmes, je ne vois pas du tout comment casser ma recursion pour la passer en iteratif. En effet, le xml est construit de la façon suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <balise1>
     <balise2>
         <balise3>  
         </balise3>  
      <balise2>
      </balise2>
         <balise3>
         </balise3>  
      </balise2>
      <balise2>
         <balise3>
         </balise3>  
      </balise2>
    </balise1>
    où chaque valeur de la balise2 depend de la valeur de la balise 1 etc... Donc dès qu'on descend à deux récursions c'est le drame (avec un nombre max de 4).

    Et contrairement à ce que j'avais écrit auparavant, je n'ai pas résolu mon problème de Statement. J'ai rajouté en début de fonction, un statement qui est manipulé tout le long (avant il était caché plus haut et jamais fermé )

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Statement stat = MainConnection.getInstance().getConnection().createStatement();
    Et je le close en sortie de fct. Je n'ai pas trouvé d'autres solutions pour manipuler deux ResultSet en même temps. En effet quand je sors de ma récursion j'ai besoin de retrouver mes valeurs précédentes.

    J'ai remonté les IOException. Et ça ne change rien.

    Le problème vient purement et simplement de la récursion. En effet quand je fais un simple appel ; en moins de 2 secondes, il arrive à me générer 2millions de lignes de XML (soit la moitié du fichier) avec plus de 200 000 enregistrements. Pour la table suivante, alors qu'on en a que 15 000 il prend un heure.

    Je ne vois plus trop quoi faire, à part casser la récursion effectivement mais là c'est le comment qui pèche. Une vague idée dans l'assemblée ?

    Bonne journée

  10. #10
    Modérateur
    Avatar de dinobogan
    Homme Profil pro
    ingénieur
    Inscrit en
    Juin 2007
    Messages
    4 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : ingénieur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 4 073
    Par défaut
    Une récursion est une simple émulation d'une pile.
    De manière très générale, supprimer la récursivité consiste à

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    1. créer une pile,
    2. mettre un premier élément dedans,
    3. dans une boucle while tant que la pile n'est pas vide faire :
      1. retirer le premier élément de la pile
      2. le traiter et ajouter des éléments dans la pile si besoin
    Dans ton cas, se sont les balises à fermer qui seront dans une pile.
    Dans un premier temps, fait une méthode non récursive en créant un fichier sans t'occuper des balises fermantes. Tu auras ensuite les idées plus claires pour voir comment ajouter les balises fermantes.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java
    Que la force de la puissance soit avec le courage de ta sagesse.

  11. #11
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    90
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2007
    Messages : 90
    Par défaut
    Ok on va tâcher de faire ça propre !

    Merci & bon week end!

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. impossible d'utiliser un xml trop gros
    Par lizard2k3 dans le forum Flex
    Réponses: 2
    Dernier message: 13/08/2008, 13h11
  2. [JDOM] Fichier XML trop gros
    Par Mygush dans le forum Format d'échange (XML, JSON...)
    Réponses: 4
    Dernier message: 06/07/2007, 12h17
  3. Fichier texte trop gros pour etre ouvert
    Par tavman dans le forum C++
    Réponses: 5
    Dernier message: 05/10/2005, 00h07
  4. ResultSet trop gros : OutOfMemoryException
    Par samsam05 dans le forum JDBC
    Réponses: 4
    Dernier message: 03/05/2005, 11h34
  5. pb avec les résultats trops gros
    Par nisaes dans le forum Bases de données
    Réponses: 2
    Dernier message: 13/01/2005, 10h44

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo