banniere

Le portail francophone de la géomatique


Toujours pas inscrit ? Mot de passe oublié ?
Nom d'utilisateur    Mot de passe              Toujours pas inscrit ?   Mot de passe oublié ?

Annonce

Rencontres QGIS 2025

L'appel à participation est ouvert jusqu'au 19 janvier 2025!

#1 Wed 26 July 2017 09:26

meonais
Participant occasionnel
Date d'inscription: 17 Jan 2017
Messages: 35

Expression rationnelle, crochet et replace

Bonjour,

J'ai fait quelques recherches et essais mais n'ai pas trouvé ou compris la réponse à mon problème

J'ai une couche de points que j'ai "snapé" à une couche de cours d'eau.
Je souhaite vérifier que le snap s'est fait sur le bon cours d'eau en comparant le champ "nom cours d'eau" de la couche de points à celui de la couche de cours d'eau.

Je ne peux pas faire un simple LIKE car la couche de points possède un champ "nom de cours d'eau" mais qui ne provient pas d'une jointure avec la couche cours d'eau que j'ai : donc je me retrouve parfois avec des chaînes de caractères différentes pour appeler un même cours d'eau. Exemple : Rivière le Lez et le Lez de sa confluence à ...

J'ai vu que la recherche plein texte serait peut être le plus efficace mais je n'ai pas trop eu l'énergie de me coller dessus...

Du coup j'ai orienté ma réflexion sur les fonctions et opérateurs de chaîne et j'envisageais ceci :
- exploser chaque champ "nom de cours d'eau"  avec par exemple :

Code:

regexp_split_to_array(upper(o.nomentiteh),E'\\s+')

- remplacer tous les mots générique (rivière, fleuve, canal, du, de, la, le...), virgules et espaces par NULL (ou '') avec replace() ou regexp_replace()

- utiliser substring(chaîne from modele) pour faire la comparaison (j'ai fait quelques tests, ça fonctionne à partir du moment où il la chaîne est strictement identique à une partie du modèle ; je ne sais pas comment instaurer % pour étendre les correspondances... )

Code:

((substring(upper((o.nom)) from o.nomentiteh) ~* upper(o.nomentiteh)) OR (substring(upper((o.nomentiteh)) from upper(o.nom)) ~* upper(o.nom)) )

- ou utiliser substring(chaîne from modele for echappement)

Mon problème principal : utilisation des atomes, contraintes, quantificateurs, échappement dans les expressions rationnelles POSIX, notamment pour gérer les [] résultants de regexp_split_to_array et à traiter avec replace() ou regexp_replace ou même substring

L'approche est-elle correcte selon vous ?
Pourriez-vous me donner un exemple qui permette de s'extraire de la présence des [] issus du split_to_array ?

Merci d'avance smile

Hors ligne

 

#2 Wed 26 July 2017 10:16

Nicolas Ribot
Membre
Lieu: Toulouse
Date d'inscription: 9 Sep 2005
Messages: 1554

Re: Expression rationnelle, crochet et replace

Bonjour,

Vous allez vous embeter en comparant les chaines: entre les accents, les différences de nom et les fautes éventuelles dans les noms.
Vous devriez plutot utiliser les outils de fuzzy match comme fuzzystrmatch, qui donnent des score de similitudes pour deux chaines.

Concernant les '[]', si je comprends bien, vous pouvez extraire les éléments d'un tableau avec unnest();
(select unnest('{A,B}'::text[])wink

Nicolas

Hors ligne

 

#3 Thu 27 July 2017 12:31

meonais
Participant occasionnel
Date d'inscription: 17 Jan 2017
Messages: 35

Re: Expression rationnelle, crochet et replace

Bonjour,

Et merci pour votre réponse !

Pour l'outil, je me suis orientée vers pg_trgm plutôt que fuzzystrmatch, j'ai mieux réussi à adapter (comprendre) l'utilisation à mon cas.
J'ai donc ce type de code :

Code:

SELECT id, ocdhydro, similarity(nomentiteh, nom) as simi,nomentiteh, nom
FROM snap_cdo
WHERE nomentiteh % nom
AND  similarity(nomentiteh, nom) > 0.5
GROUP BY id, ocdhydro, nomentiteh, nom
ORDER BY id, ocdhydro ASC ;

Je ne comprends pas bien pourquoi j'ai des enregistrements qui sont bien sélectionnés (note sup à 0.5) et d'autres non (note < 0.5) alors que les correspondances semblent similaires... Voici un exemple de sortie avec > 0.5

Code:

id|ocdhydro|simi|nomentiteh|nom
31|ocdhydro|0.529412|rivière la drôme|La Drôme
32|ocdhydro|0.611111|rivière le roubion|Le Roubion
33|ocdhydro|0.590909|ruisseau les collières|les Collières
34|ocdhydro|0.529412|rivière l'eygues|l'Eygues
35|ocdhydro|0.578947|rivière la bresque|La Bresque
36|ocdhydro|0.666667|rivière le gardon de saint-jean|le Gard et le Gardon de Saint Jean
37|ocdhydro|0.555556|torrent la bévéra|La Bévéra
38|ocdhydro|0.55|le grand anguillon|L'Anguillon
39|ocdhydro|0.611111|rivière la galaure|la galaure
40|ocdhydro|0.5625|rivière la payre|La Payre
41|ocdhydro|0.533333|fleuve le tech|le Tech
42|ocdhydro|0.6|rivière la gervanne|La Gervanne
43|ocdhydro|0.55|ruisseau la cadière|la Cadière
(...)

et maintenant avec <0.5

Code:

id|ocdhydro|simi|nomentiteh|nom
 1| V40-0400 |    0.375 | rivière la vére                                | Vére
 2| V40-0400 |    0.375 | rivière la vére                                | Vére
 3| V50-0400 | 0.333333 | rivière l'ardèche                               | l'ardeche
 4| V50-0400 | 0.333333 | rivière l'ardèche                               | l'ardeche
 5| V50-0400 | 0.333333 | rivière l'ardèche                               | l'ardeche
 6| V34-0400 |   0.4375 | ruisseau l'oron                                 | l'Oron
 7| V50-0400 | 0.333333 | rivière l'ardèche                               | l'ardeche
 8| V50-0400 | 0.333333 | rivière l'ardèche                               | l'ardeche
 9| V---0000 | 0.315789 | fleuve le rhône                                 | le rhone
 10| V3--3002 | 0.315789 | fleuve le rhône                                 | le rhone
 11| V52-0400 | 0.384615 | rivière le lez                                  | le lez
 12| V52-0400 | 0.384615 | rivière le lez                                  | le lez
 13| V52-0400 | 0.384615 | rivière le lez                                  | le lez
 14| V52-0400 | 0.384615 | rivière le lez                                  | le lez
 15| V52-0400 | 0.384615 | rivière le lez                                  | le lez
 16| V52-0400 | 0.384615 | rivière le lez                                  | le lez
 17| V52-0400 | 0.384615 | rivière le lez                                  | le lez
 18| V52-0400 | 0.384615 | rivière le lez                                  | le lez
 19| V52-0400 | 0.384615 | rivière le lez                                  | le lez
 20| V50-0400 | 0.333333 | rivière l'ardèche                             | l'ardeche
 21| V50-0400 | 0.333333 | rivière l'ardèche                             | l'ardeche
 22|          | 0.333333 | rivière l'ardèche                               | l'ardeche
 23| V50-0400 | 0.333333 | rivière l'ardèche                            | l'ardeche
 24| V5310500 | 0.466667 | rivière l'oule                                  | L'Oule
 25| V71-0400 | 0.368421 | rivière le gard                                 | le Gardon
 26| V71-0400 | 0.368421 | rivière le gard                                 | le Gardon
(...)

C'est pourquoi je voudrais arriver à "supprimer" les mots "parasites" dans chacun des champs avant de faire la comparaison (hier j'étais partie sur le regexp_split..() pour ensuite faire un replace() des mots "parasites", d'où ma demande sur []). Cette "suppression" me permettrait de mieux gérer les résultats de similarity(), non ?

Hors ligne

 

#4 Thu 27 July 2017 13:24

Nicolas Ribot
Membre
Lieu: Toulouse
Date d'inscription: 9 Sep 2005
Messages: 1554

Re: Expression rationnelle, crochet et replace

Bienvenu dans le monde de la comparaison de chaines big_smile
(moi perso, je n'ai jamais reussi a faire un truc clean lors de la comparaison de chaines)

Vous pouvez eventuellement normaliser un peu les données avant, en supprimant les accents et autres signes, avec unaccent (https://www.postgresql.org/docs/9.6/sta … ccent.html)

Nicolas

Hors ligne

 

#5 Thu 27 July 2017 13:53

tumasgiu
Membre
Lieu: Ajaccio
Date d'inscription: 5 Jul 2010
Messages: 1159

Re: Expression rationnelle, crochet et replace

Salut,

je remarque que les noms issus de l'exemple <0.5 ont tous beaucoup de caractères blancs en fin de chaine.
Etant donné que pg_trgm compare le nombre de trigramme communs, il est probable que ceux générés par ces
blancs fassent baisser le score.
Un petit coup de trim pourrait peut être améliorer çà.

Hors ligne

 

#6 Thu 27 July 2017 14:15

meonais
Participant occasionnel
Date d'inscription: 17 Jan 2017
Messages: 35

Re: Expression rationnelle, crochet et replace

big_smile

Je vous adore ! : cool

Merci beaucoup, ça aide bien. Je pense que ça suffira pour discriminer les quelques erreurs de snap sur mon jeu de données, avec un autre filtre / jointure sur des champs smile

Encore merci

Dernière modification par meonais (Mon 31 July 2017 16:56)

Hors ligne

 

#7 Thu 27 July 2017 14:57

JRM
Participant assidu
Lieu: Arras
Date d'inscription: 15 Apr 2009
Messages: 521

Re: Expression rationnelle, crochet et replace

C'est pourquoi je voudrais arriver à "supprimer" les mots "parasites"


Une première passe avec Full Text Search et ses fonctions to_tsvector() et  to_tsquery() va te permettre de normaliser tes mots (lexemes) et de réduire les variances en remontant à la racine du terme.

Tu peux utiliser le résultat avec pg_trm, ça permet de réduire les faux positifs et les mots parasites. On peut encore en rajouter une couche avec l'extension unaccent.

Hors ligne

 

#8 Thu 27 July 2017 14:57

meonais
Participant occasionnel
Date d'inscription: 17 Jan 2017
Messages: 35

Re: Expression rationnelle, crochet et replace

Ha oups...

Il y a du mieux avec unaccent() mais pas encore ça... j'ai tenté trim et regexp_replace mais pas vraiment de succès :
J'ai même l'impression d'avoir de moins bons résultats ? ...

Code:

plagepomi=# SELECT id, ocdhydro, similarity(unaccent(trim(trailing '\s+' from nomentiteh)), unaccent(trim(trailing '\s+' from nom))) as simi,nomentiteh, nom
plagepomi-# FROM snap_cdo
plagepomi-# WHERE nomentiteh % nom
plagepomi-# AND  similarity(unaccent(trim(trailing '\s+' from nomentiteh)), unaccent(trim(trailing '\s+' from nom))) < 0.5
plagepomi-# GROUP BY id, ocdhydro, nomentiteh, nom
plagepomi-# ORDER BY id, ocdhydro ASC ;


id | ocdhydro |   simi   |                   nomentiteh                    |                nom
------------+----------+----------+-------------------------------------------------+------------------------------------
10124   | V40-0400 |    0.375 | riviÞre la vÚore                                | VÚore
10301   | V3530500 | 0.384615 | riviÞre l'ay                                    | L'Ay
22336   | V34-0400 |   0.4375 | ruisseau l'oron                                 | l'Oron
32046   | V52-0400 | 0.384615 | riviÞre le lez                                  | le lez
33548   | V5310500 | 0.466667 | riviÞre l'oule                                  | L'Oule
33873   | V71-0400 | 0.368421 | riviÞre le gard                                 | le Gardon
34885   | V52-0400 | 0.384615 | riviÞre le lez                                  | le lez
35097   | Y25-0400 | 0.461538 | fleuve l'orb                                    | l'Orb
43739   | Y4--0200 | 0.428571 | riviÞre l'arc                                   | l'Arc
44196   | V5440500 |     0.35 | riviÞre l'auzonnet                              | L'Auzon
44292   | V6150500 | 0.333333 | riviÞre la sorgue                               | la sorgue de velleron
44293   | V5440500 |     0.35 | riviÞre l'auzonnet                              | L'Auzon
48817   | V71-0400 | 0.365385 | ruisseau le gardon de saint-martin de lansuscle | le Gard et le Gardon de Saint Jean
48986   | Y3130500 |    0.375 | ruisseau du coulazou                            | le Coulazou
52033   | Y2030500 | 0.428571 | riviÞre la vis                                  | la vis

Je vais voir la combinaison proposée par JRM smile

Dernière modification par meonais (Thu 27 July 2017 15:11)

Hors ligne

 

#9 Thu 27 July 2017 15:30

JRM
Participant assidu
Lieu: Arras
Date d'inscription: 15 Apr 2009
Messages: 521

Re: Expression rationnelle, crochet et replace

Pour ne pas te prendre la tête aujourd’hui avec des histoire d'immutabilité, tu peux te créer de nouvelles colonnes telles que nomentiteh_trigram que tu remplis avec

Code:

replace(strip(to_tsvector('simple', unaccent(nomentiteh)))::text,'''', '')

puis index avec

Code:

gin (nomentiteh_trigram gin_trgm_ops)

.

Dernière modification par JRM (Thu 27 July 2017 15:31)

Hors ligne

 

#10 Thu 27 July 2017 18:23

meonais
Participant occasionnel
Date d'inscription: 17 Jan 2017
Messages: 35

Re: Expression rationnelle, crochet et replace

Bonsoir,

Merci JRM pour le bout de code, ça permet d'aller plus vite smile
Moi qui ne voulait pas trop aller dans le plein texte par manque de temps pour se former... j'y suis jusqu'au cou !  big_smile

Du coup, j'ai le même type de résultats, même sans les accents et les apostrophes, je dois utiliser un pg_trgm > 0.4, mais c'est parce que je peux visualiser rapidement l'ensemble de mes données...

Donc maintenant que j'y suis jusqu'au cou, j'aimerais arriver à indiquer au dictionnaire 'stop' les mots à ne pas comptabiliser. J'ai trouvé le fichier et rajouté les mots à "supprimer" (riviere, ruisseau, ru, ravin, canal, bief, ...) mais j'ai encore le même type de résultats...

J'ai lancé

Code:

CREATE TEXT SEARCH DICTIONARY public.simple_dict(
TEMPLATE=pg_catalog.simple, 
STOPWORDS=french);

j'ai complété le fichier C:\Program Files\PostgreSQL\9.5\share\tsearch_data\french.stop avec les mots que je ne voulais plus être intégrés dans la recherche, dont "riviere"

J'ai testé sous psql (et sql de pgAdmin) et obtenu :

Code:

plagepomi=# SELECT ts_lexize('french_stem', 'riviere');
 ts_lexize
-----------
 {}
(1 ligne)

Mais quand je lance ma requête pg_trgm, j'ai toujours les mêmes valeurs et donc la même liste d'enregistrements <0.5 alors qu'ils devraient (si j'ai bien tout compris) avoir des "notes" de similarity() plus grande sans les mots "parasites" comme "riviere", non ?

Je vais laisser maturer ce soir mais si vous avez d'autres aiguillages, je veux bien !

Merci beaucoup,

Hors ligne

 

Pied de page des forums

Powered by FluxBB