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

Langage SQL Discussion :

[PostgreSQL] identification de chaines ressemblantes


Sujet :

Langage SQL

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Inscrit en
    Janvier 2006
    Messages
    71
    Détails du profil
    Informations forums :
    Inscription : Janvier 2006
    Messages : 71
    Par défaut [PostgreSQL] identification de chaines ressemblantes
    J’ai un problème qui me paraît pas si compliqué mais dont je n’arrive pas à me dépétrer. Comme il est assez intéressant et susceptible d'être utile à d'autres, je vous le soumets :

    J’ai deux tables (j’utilise PostgreSQL) :

    CREATE TABLE a
    (
    id_alphanum varchar(70) NOT NULL,
    CONSTRAINT pk_a PRIMARY KEY (id_alphanum)
    ) ;

    CREATE TABLE b
    (
    id_num varchar(30) NOT NULL,
    id_alphanum(70),
    CONSTRAINT pk_b PRIMARY KEY (id_num)
    ) ;

    Les identifiants alphanumériques sont des descripteurs de lieux, par exemple ‘ruederivoli’.
    Comme les concepteurs de la table a et de la table b ne sont pas les mêmes, les id_alphanum ne coïncident pas alors qu’ils décrivent les mêmes objets. Par exemple, ‘rue de Rivoli’ (avec espace, lettres capitales et article) vs. ‘ruerivoli’ (minimaliste).

    Mon problème est d’identifier, en vue d’une mise à jour, les id_alphanum de la table b avec ceux de la table a. J’ai déjà écrit une fonction distance_mots(varchar,varchar) qui me retourne la distance entre deux mots : zéro si ce sont les mêmes mots et +1 à chaque opération ajout de caractère/suppression (c’est la distance de Levenshtein pour ceux que ça intéresse).

    Je cherche à produire une requête qui m’affiche tous les a.id_alphanum avec en regard le b.id_alphanum le plus proche.
    Je m’empatouille avec les GROUP BY, les MIN etc, mais je n'arrive pas à ce résultat. Si vous avez une idée de génie, je suis preneur.

    Merci à la communauté


    Sakalam

  2. #2
    Membre Expert

    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 683
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 683
    Par défaut
    Les différences sont uniquement des espaces en plus ? Ou tu as d'autres types de différences ?

    edit : j'ai relu ton message que j'avais lu très vite. Si tu as déjà ta fonction de "rapprochement" il faut que tu fasse une jointure entre les deux tables. La condition de jointure pourrait être fonction de la distance de levenstein maxi de tes deux noms.

    exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    select 	a.id_alphanum, 
    	b.id_alphanum 
    from a 
    	inner join b 
    		on distance_mots(a.id_alphanum, b.id_alphanum ) < 2
    Cette requête retournera les id_alphanum de a qui ont dans b une distance inférieure a 2.

  3. #3
    Membre confirmé
    Inscrit en
    Janvier 2006
    Messages
    71
    Détails du profil
    Informations forums :
    Inscription : Janvier 2006
    Messages : 71
    Par défaut
    Les différences peuvent être n'importe quoi : des articles rajoutés (par exemple 'place concorde' doit concorder avec 'place de la concorde'), des majuscules/minuscules, des lettres accentuées ou pas.

    Mais les différences sont relativement "bien" gérées par la fonction que j'ai écrite

    distance_mots('placeconcorde','Place de la Concorde') retourne 9
    distance_mots('placeconcorde','Place de la Madeleine') retourne 15

    Mais il faut que je mette ensemble cette fonction avec des MIN etc. pour mettre en face de chacun des id_alphanum de la table a, l'id_alphanum de la table b le plus proche.

    edit : Merci ! moi-même j'ai répondu avant ton edit (on n'en sort pas!). Ta méthode marche (en ramant un poil), mais je me demandais s'il n'y avait pas un moyen d'obtenir le minimum plutôt que ceux "assez proche" (cad distance<2 comme tu le suggères). En tous cas, j'ai une bonne base.

    S.

  4. #4
    Membre Expert

    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 683
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 683
    Par défaut attention
    voilà :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    SELECT 	a.id_alphanum, 
    	b.id_alphanum 
    FROM a 
    	INNER JOIN b
    		ON distance_mots(a.id_alphanum,b.id_alphanum) = (	SELECT MIN(distance_mots(a.id_alphanum,b2.id_alphanum)) 
    									FROM b b2
    edit : Attention cependant car :
    - la distance de levenshtein peut rapprocher des choses que tu ne rapprocherais "logiquement" pas d'après les exemples que tu m'a montrés
    - tu pourras avoir de multiples lignes de la table b rapprochées d'une seule ligne de la table a

    Ceci doit te faciliter le travail pour la plupart des cas mais une grosse relecture doit être faite. Ou mieux analyser ton problème pour avoir des résultats automatiques plus fiables.

  5. #5
    Membre Expert

    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 683
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 683
    Par défaut
    D'ailleurs pour compléter et avoir une approche qui colle plus à ta problématique, je viens de penser que seuls les noms propres doivent être utilisés pour rapprocher tes lieux grâce à la distance de Levenshtein.

    Le mauvais exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    distance_mots("champsdemars", "champselysees")
     > 6
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    distance_mots("avenuedeschampselysees", "champselysees")
     > 9
    Ici on voit de suite le problème que tu peux rencontrer.

    Je te suggère donc de passer tes lieux à travers une fonction qui enlève tout ce qui relève des appelations de voie (place, avenue, rue, ...) ainsi que des articles (de, la, les, ...) avant de calculer la distance de Levenshtein.


    Ca donnerait :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    distance_mots("mars", "champselysees")
     > 11
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    distance_mots("champselysees", "champselysees")
     > 0
    Tu me diras que les articles, s'ils sont collés aux noms du fait du manque d'espaces, seront impossible à sortir avec une fonction. Peut être ne retirer que les appellations de voierie.

    A méditer...

  6. #6
    Membre confirmé
    Inscrit en
    Janvier 2006
    Messages
    71
    Détails du profil
    Informations forums :
    Inscription : Janvier 2006
    Messages : 71
    Par défaut Ca roule
    Merci pour tes conseils.

    Avec les données dont nous disposons, la distance de Levenshtein devrait suffire, mais effectivement pour des cas plus élaborés, je pense raffiner la fonction écrite.
    J'ai pris bonne note que ta requête pouvait retourner plusieurs associations : toutes celles dont le calcul donne le minimum.

    Merci pour ton aide

    S.

  7. #7
    Membre Expert

    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 683
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 683
    Par défaut
    Je te conseille tout de même de supprimer les appellations de voierie c'est très simple à réaliser (du replace en masse) et ça te donnera de suite de bien meilleurs résultats.

    Bonne chance

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

Discussions similaires

  1. [PostgreSQL] [PostGreSQL] Comparaison de chaines de caractères
    Par ryu20 dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 10/07/2008, 15h11
  2. Postgresql et la chaine vide
    Par gege22mars dans le forum PostgreSQL
    Réponses: 3
    Dernier message: 10/09/2007, 00h30
  3. [PostgreSQL] [PostGreSQL] Trouver les ' et les remplacer par \' dans une chaine
    Par bossLINDROS dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 03/05/2007, 10h31
  4. Identification d'une chaine de caractère null
    Par jacques70 dans le forum Langage
    Réponses: 9
    Dernier message: 11/05/2006, 17h14
  5. PostGreSQL 8 : ODBC, OLEDB, ADO et chaine de connection
    Par romeo9423 dans le forum PostgreSQL
    Réponses: 1
    Dernier message: 25/01/2005, 09h38

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