TABLEAU VERS SELECTION via SELECTION LIMITE VERS TABLEAU (en boucle)

Bonjour,

pour modifier un grand nombre d’enregistrement (tout ou partie d’une grosse table), je n’ai pas utilise TABLEAU VERS SELECTION bien pratique dans des boucles de traitements utilisant la commande SELECTION LIMITE VERS TABLEAU, car “tableau vers selection” remplace “TOUTE” la selection et non pas la partie de selection limite qui est traite.

Vu que j’ai vraiment ete oblige de modifier ces enregistrements (traitement sur 41 millions de fiches) et vu le nombre, n’utiliser que des tableaux, je me suis repenche sur le probleme , et la solution est bien simple … et probablement deja sur le forum mais je n’avais pas trouve …

  • creer une selection sur tous les enregistrements a traiter
    => COPIER SELECTION([TABLE_A_TRAITER];“selection”)

SELECTION LIMITE VERS TABLEAU : utiliser un tableau avec les numeros d’enregistrements de cette selection
=> CREER SELECTION SUR TABLEAU([TABLE_A_TRAITER];$SEL;“ens”)
// faire le traitement dans le (les) tableau(x)

=> UTILISER SELECTION(“ens”)
TABLEAU VERS SELECTION($RESULT;[TABLE_A_TRAITER]champ)

=> revenir a la selection de depart
UTILISER SELECTION(“selection”)

La boucle SELECTION LIMITE VERS TABLEAU continue a la bonne suite

Cerise sur le gateau : LE CACHE
Si le contenu du cache est inutile et que les donnees sont assez volumineuses, le cache va se vider de 10% a chaque fois qu’il est plein. Cela peut ralentir le traitement a chaque vidage du cache.
Pour que le cache se vide moins souvent, donc beaucoup plus que 10%, il y a une commande que je viens de tester et qui fonctionne bien :
$cache:=Lire taille cache
FIXER TAILLE CACHE($currentCache;$cache/2) // 50% du cache est vide au lieu de 10%, donc moins frequement

exemple de code qui traite 41 millions de pages web avec du texte extrait pour chaque page :
<code 4D>

C_TEXTE($eviter;$txtlem1)
C_ENTIER LONG($i;$a)
C_ENTIER LONG($POFD;$POFF;$pass;$blc;$lTailleSel;$lMaxPage;$POTD;$POTF;$T1)
C_BOOLEEN($deja_bol;$trouvfinal)
TABLEAU TEXTE($motscles;0)
TABLEAU TEXTE($data;0)
TABLEAU TEXTE($lemme;0)
TABLEAU TEXTE($RESULT;0)
TABLEAU ENTIER LONG($SEL;0)
TABLEAU TEXTE($FINAL_MOT;0)
TABLEAU TEXTE($FINAL_LEM1;0)

C_REEL($currentCache;$cache;$T2)
$currentCache:=Lire taille cache

//%R-
TOUT SELECTIONNER([TOUS_MOTS]) // 3 millions de mots differents en reference
$t1:=Nombre de millisecondes

SELECTION VERS TABLEAU([TOUS_MOTS]mot;$FINAL_MOT;[TOUS_MOTS]lemme1;$FINAL_LEM1)
TRIER TABLEAU($FINAL_MOT;$FINAL_LEM1;>)
TOUT SELECTIONNER([PAGES_CRAWL]) // 41 millions de fiches
COPIER SELECTION([PAGES_CRAWL];“selection”)
$eviter:=" de du un une sur a en le la les des sur vers aux dans ces ses sont pas ne nous vous il elle ils elles "
$lMaxPage:=2000
$lTailleSel:=Enregistrements trouves([PAGES_CRAWL])
$blc:=0
$pass:=0
Boucle ($lPage;1;1+(($lTailleSel-1)$lMaxPage))
SELECTION LIMITEE VERS TABLEAU(1+($lMaxPage*($lPage-1));$lMaxPage*$lPage;[PAGES_CRAWL];$SEL;[PAGES_CRAWL]mot_cle;$data)
$taille:=Taille tableau($data)
TABLEAU TEXTE($RESULT;$taille)
CREER SELECTION SUR TABLEAU([PAGES_CRAWL];$SEL;“ens”)

Boucle ($i;1;$taille)
	$pass:=$pass+1
	$blc:=$blc+1
	Si ($pass=100)  // n'afficher le message que les 100 boucles
		$T2:=(Nombre de millisecondes-$T1)/$blc
		MESSAGE(Chaine($blc)+"/"+Chaine($T2))
		$pass:=0
		  //$t1:=Nombre de millisecondes
	Fin de si 
	
	LIRE MOTS CLES TEXTE($data{$i};$motscles;*)
	  //CHERCHER PAR TABLEAU([TOUS_MOTS]mot;$motscles)
	  //VALEURS DISTINCTES([TOUS_MOTS]lemme1;$FINAL_MOT) => teste et bcp moins rapide
	$txtlem1:=""
	Boucle ($a;1;Taille tableau($motscles))
		$motA:=$motscles{$a}
		Si (Position(" "+$motA+" ";$eviter;1)=0)
			$deja_bol:=Faux
			$trouvfinal:=Faux
			$trouvfinal:=Chercher dans tableau trie($FINAL_MOT;$motA;>;$POFD;$POFF)
			$lemme1:=""
			Si ($trouvfinal)
				$lemme1:=$FINAL_LEM1{$POFF}
				$deja_bol:=Chercher dans tableau trie($LEMME;$lemme1;>;$POTD;$POTF)
				Si ($deja_bol)
				Sinon 
					INSERER DANS TABLEAU($LEMME;$POTD)
					$LEMME{$POTD}:=$lemme1
					$RESULT{$i}:=$RESULT{$i}+$lemme1+" "
				Fin de si 
			Fin de si 
		Fin de si 
	Fin de boucle 
Fin de boucle 
UTILISER SELECTION("ens")
TABLEAU VERS SELECTION($RESULT;[PAGES_CRAWL]mot_cle_lemme1)
UTILISER SELECTION("selection")
$cache:=Lire taille cache
FIXER TAILLE CACHE($currentCache;$cache/2)

Fin de boucle
//%R+

</code 4D>

Pensez-vous qu’il puisse exister quelques micro secondes a gagner encore?

Il y a environ 1 milliard de boucle au total, 20 mots en moyenne retenus par page web.

Merci

en premiere approche, car pas creuse du detail des 2 boucles internes…
? supprimer les lignes 23, 24, 72
? inserer TOUT SELECTIONNER([PAGES_CRAWL]) apres la ligne 31 (toujours entendu dire que c’est une commande tres econome�c)
? ligne 34, enlever le 3ieme parametre “ens”
? supprimer la ligne 70
je te dis pas que ca va aller mieux, c’est simplement que tu as des selections en memoire, ca ne me semble pas utile.

A voir comme ca, j’essaierai bien de fixer $lMaxPage a beaucoup plus que 2 000 ; genre 10 000 ou meme 100 000 : tu as essaye ?

: Arnaud DE MONTARD

? ligne 34, enlever le 3ieme parametre “ens”
? supprimer la ligne 70

Si tu fait ca, tu va sans cesse modifier les 2000 premieres fiches de ta selection des 41 millions (toutes) et pas sur la selection des fiches encours dans ta boucle SELECTION LIMITE ? Non ?

pourtant j’ai teste, c’est toujours les 2000 memes prelieres fiches qui sont modifiees, et pas les suivantes …

Oui pour TOUT SELECTIONNER, c’est ce que tout le monde dis …

Ah oui, je vois, CREER SELECTION SUR TABLEAU, le 3eme parametre peut etre omis et s’applique sur la selection courante, ce qui evite le UTLISER SELECTION(nom) c’est ca? tu gagne une ligne puisque c’est sur la selection courante en fait ?

En optimisant au maximum, je descends pas en dessous de 1 milliseconde par mot …

Il faut que je reduise la taille du tableau TOUS_MOTS bien en dessous de 3 million … je ne vois plus que ca.
Sinon, ca mouline 11 jours 24/24 pour tout traiter … Peut etre des tableaux de ref par lettre alpha …

Un gain important se situe en ligne 52.

Vouloir eviter les mots creux n’est pas necessaire et fait perdre bcp de temps. Cela se comprend dans la mesure ou pour eviter un mot, on va appliquer a chacun de tous les autres mots une operation de POSITION qui est lourde et inutile. Autant les laisser, et les supprimer seulement d’une partie “recherche”.

Exemple de requete : “La petite maison dans la prairie”;
tous les mots sont bien stockes (la, dans, petite …), mais on enlevera de la recherche les mots “la” et “dans”.

Le gain de vitesse est de 20% …

La taille du tableau des mots de reference ne donne quasiment pas de gain entre 1 tableau de 1million et 3 millions de mots avec CHERCHER DANS TABLEAU TRIE (ca fuse vraiment vite cette commande :smiley: ).

Dernier petit gain, en supprimant l’etoile dans la commande LIRE MOT CLE TEXTE , mais c’est a tester selon le contenu du texte. Dans mon cas, je n’ai pas trop de doublons , donc c’est plus rapide sans l’etoile.
C’est cette partie qui semble le plus ralentir le processus. En essayant de scinder les mots avec “POSITION”, c’est moins rapide.

Au global, je n’arrive pas a descendre en dessous des 1000 mots/sec sur mon MacBook Pro.

Marc,

Dernier truc bete : ton MacBook Pro a un disque SSD? Je pense que oui mais si ce n’etait pas le cas c’est LE critere le plus important pour des traitements lourds modifiant des donnees comme dans ta methode ci-dessus. Dans notre boite, c’est bien simple : on a que des PC mais on a achete expres un Mac avec SSD pour mettre a jour nos grosses bases clients (compactages, index) et on divise nos temps de traitement pas 20 par rapport a nos PC “bete de course”…

Bon courage pour tes 11 jours de traitement, ca doit tourner encore depuis dimanche dernier :cry: :cry: :cry:

Bye.

Bonjour,

oui helas c’est deja du SSD derniere generation (1To sur le macbook et 4To sur le Mac Pro)… Vu que la moulinette est longue, plusieurs traitements vont etre faits dans les boucles.

Ce qui mange vraiment du temps, c’est de separer le texte en mots cle. Il y a peut-etre une astuce… ?

Merci ^^

: Marc LONGO

Ce qui mange vraiment du temps, c’est de separer le texte en mots
cle. Il y a peut-etre une astuce… ?
Tu veux dire que c’est LIRE MOTS CLES TEXTE le plus chronophage ? Je ne vois pas trop ce qui te permettrait d’aller plus vite ; peut-etre la methode que je t’avais envoye, si elle est compilee dans un composant, mais j’en doute.
Sinon, j’etudierais bien le temps des 2 Chercher dans tableau trie, car si j’ai bien compris l’un des 2 au moins travaille sur 3 millions de lignes. Tu as mesure cette partie la ?

: Arnaud DE MONTARD

Tu veux dire que c’est LIRE MOTS CLES TEXTE le plus chronophage ? Je
ne vois pas trop ce qui te permettrait d’aller plus vite ; peut-etre
la methode que je t’avais envoye, si elle est compilee dans un
composant, mais j’en doute.
Oui c’est la plus chronophage … j’ai essaye pleins de methodes et plugins, mais ca reste legerement moins rapide que LIRE MOTS CLES TEXTE . En supprimant l’etoile, c’est un peu plus rapide puisque j’ai peu de mots en double.

On avait deja eut une discussion que je ne retrouve pas, une histoire de blob vers tableau texte je crois …
il y a surement moyen d’avoir une fonction plus rapide, mais ca reste dans le fin fond de la ram et difficilement programmable sous 4D …

: Arnaud DE MONTARD

Sinon, j’etudierais bien le temps des 2 Chercher dans tableau trie,
car si j’ai bien compris l’un des 2 au moins travaille sur 3 millions
de lignes. Tu as mesure cette partie la ?
Oui, entre un tableau de 3 millions de lignes et un autre de seulement 1 million, je n’arrive meme pas a mesurer la difference, elle est si infime que ca vaut pas le coup, et meme le coup au contraire de charger autant que le besoin le tableau de reference.

Oups, erreur sur la duree totale, 12h de traitement pour 41 millions de fiches et pas 11 jours …

De nombreux tests donnent des infos etonnantes, notament sur la necessite de remettre les valeurs a zero (taille tableau, selection …) au risque de voir s’effondrer la vitesse tres rapidement.

Autre indication des tests, si l’on doit chercher dans un tableau trie, il faut que celui-ci soit de bonne taille, sinon, pour eviter des doublons dans une chaine texte assez courte (moins de 30 mots environs), il est preferable d’utiliser la commande “POSITION”, c’est un peu plus rapide.

Voici le code le plus rapide que j’ai pu obtenir :

La boucle commence avec 0,5 milliseconde par enregistrement traite pour finir vers 1,1 miliseconde en moyenne sur les 41 millions de pages web du moteur de recherche (zone titre et balise H1 si elle existe) :

<code 4D>
C_TEXTE($eviter;$txtlem1)
C_ENTIER LONG($i;$a)
C_ENTIER LONG($POFD;$POFF;$pass;$blc;$lTailleSel;$lMaxPage;$POTD;$POTF;$T1)
C_BOOLEEN($deja_bol;$trouvfinal)
TABLEAU TEXTE($motscles;0)
TABLEAU TEXTE($data;0)
TABLEAU TEXTE($lemme;0)
TABLEAU TEXTE($RESULT;0)
TABLEAU ENTIER LONG($SEL;0)
TABLEAU TEXTE($FINAL_MOT;0)
TABLEAU TEXTE($FINAL_LEM1;0)

C_REEL($currentCache;$cache;$T2)
$currentCache:=Lire taille cache
FIXER TAILLE CACHE($currentCache;$cache/2)

//%R-
TOUT SELECTIONNER([FINAL]) // 3 millions de mots differents en reference

SELECTION VERS TABLEAU([FINAL]mot;$FINAL_MOT;[FINAL]lemme1;$FINAL_LEM1)
TRIER TABLEAU($FINAL_MOT;$FINAL_LEM1;>)
TOUT SELECTIONNER([TABLE_DOC2]) // 41 millions de fiches

$eviter:=" de du un une sur a en le la les des sur vers aux dans ces ses sont pas ne nous vous il elle ils elles "
$lMaxPage:=500
$lTailleSel:=Enregistrements trouves([TABLE_DOC2])
$blc:=0
$pass:=0
$t1:=Nombre de millisecondes

Boucle ($lPage;1;1+(($lTailleSel-1)$lMaxPage))
TABLEAU ENTIER LONG($SEL;0)
TABLEAU TEXTE($data;0)
TABLEAU TEXTE($RESULT;0)

SELECTION LIMITEE VERS TABLEAU(1+($lMaxPage*($lPage-1));$lMaxPage*$lPage;[TABLE_DOC2];$SEL;[TABLE_DOC2]mot_cle;$data)
$taille:=Taille tableau($data)
CREER SELECTION SUR TABLEAU([TABLE_DOC2];$SEL)
TABLEAU TEXTE($RESULT;$taille)
Boucle ($i;1;$taille)
	$RESULT{$i}:=""
	$pass:=$pass+1
	$blc:=$blc+1
	Si ($pass=2000)  // n'afficher le message que les 100 boucles
		$T2:=(Nombre de millisecondes-$T1)/$blc
		MESSAGE(Chaine(Taille tableau($motscles))+" : "+Chaine($blc)+"/"+Chaine($T2))
		$pass:=0
	Fin de si 
	TABLEAU TEXTE($motscles;0)
	
	LIRE MOTS CLES TEXTE($data{$i};$motscles)
	
	Boucle ($a;1;Taille tableau($motscles))
		  //$motA:=$motscles{$a}
		$trouvfinal:=Chercher dans tableau trie($FINAL_MOT;$motscles{$a};>;$POFD;$POFF)
		Si ($trouvfinal)
			Si (Position($FINAL_LEM1{$POFF};$RESULT{$i};1;*)=0)
				$RESULT{$i}:=$RESULT{$i}+$FINAL_LEM1{$POFF}+" "
			Fin de si 
			
			
			  //************ moins rapide que POSITION
			  //Si (Non($deja_bol))
			  //INSERER DANS TABLEAU($LEMME;$POTD)
			  //$LEMME{$POTD}:=$lemme1
			  //$RESULT{$i}:=$RESULT{$i}+$lemme1+" "
			  //Fin de si 
			  //************ 
			
		Fin de si 
	Fin de boucle 
Fin de boucle 
TABLEAU VERS SELECTION($RESULT;[TABLE_DOC2]mot_cle_lemme1)
REDUIRE SELECTION([TABLE_DOC2];0)
TOUT SELECTIONNER([TABLE_DOC2])

Fin de boucle
//%R+

</code 4D>

Ca semble difficile de traiter plus vite …