9
votes

PostgreSQL et jeux de mots

Dans un jeu de mots similaire à la ruée ou à la typographie, où les utilisateurs doivent construire des mots sur un ensemble donné de lettres:

 Entrez la description de l'image ici

Je garde mon dictionnaire dans une simple table SQL: xxx

car la durée du jeu est très courte ne veulent pas vérifier tous les mots saisis en appelant un script PHP, ce qui aurait l'air de ce mot dans la table Good_words .

à la place, je voudrais télécharger tous les mots possibles par Un script PHP appelle avant que le tour commence - puisque toutes les lettres sont connues.

Ma question est la suivante: S'il y a une belle façon squis de trouver de tels mots? < p> Je pourrais exécuter un script plus long une fois pour ajouter une colonne à Good_words TABLE, qui aurait la même lettre que dans le mot Word colonne, mais triés alphabétiquement ... mais je Je ne peux toujours pas penser à un moyen de faire correspondre un ensemble de lettres.

et faire le mot correspondant à l'intérieur d'un script PHP (contre à l'intérieur de la base de données) prendrait probablement trop de temps (à cause de bande passante: devrait aller chercher à chaque rangée de la base de données sur le script php).

Toute suggestions ou informations s'il vous plaît?

Utilisation de PostgreSQL-8.4.13 avec CENTOS Linux 6.3.

mise à jour:

Autres idées J'ai:

  1. Créez un script en cours d'exécution constamment (Cronjob ou Daemon) qui pré-remplissez une table SQL avec une carte de lettres précompilée et des mots possibles - mais ressemble toujours à un gaspillage de bande passante et de la CPU, je préférerais résoudre ce problème à l'intérieur de la base de données
  2. Ajouter des colonnes entières A , b , ..., z et chaque fois que je stocke un mot dans Good_words , stockez la lettre se terminant. Je me demande S'il est possible de créer un déclencheur d'insertion dans PL / PGSQL Pour ça?

5 commentaires

A) Cela va probablement toujours être une liste très longue de mots qui doit être téléchargée là-bas, B) qui donne à un utilisateur technique un excellent moyen de tricher. ;)


En fait, non: Roulez les rapports Nombre de mots possibles à la fin des rondes et que le nombre dépasse rarement 300. Même avec une longueur de mots supposée de 10 lettres qui seraient simplement de 3 kbyte - avant la gzipping.


Pouvez-vous télécharger une vidange CSV de Good_words Table d'un endroit pour jouer avec? Ou fournir une autre source, s'il vous plaît?


Ce sera vraiment inefficace. Vous devriez presque certainement cacher la liste de mots de la base de données en tant que fichier compressé que le client effectue une demande HTTP simple. Vous pouvez définir des en-têtes HTTP modifiés si vous éviterez la récupération si elle n'a pas changé. Si cette liste de mots devient trop grosse, ce que vous faites est de créer un sous-ensemble de mots les plus fréquemment essayés (pas nécessairement corrects de mots) que vous avez mis dans le cache du client, et si le cache du client ne connaît pas le mot qui lui demande le serveur. via une demande de service Web. Le client peut ajouter la liste de mots téléchargée à SQLite, BDB ou similaire pour la recherche rapide.


+1 pour une idée intéressante sur la pré-mise en cache des mots communs dans l'application :-)


7 Réponses :


1
votes

Créer une table qui comporte des entrées (ID, CHAR), nez le nombre de caractères que vous interrogez. XXX PRE>

ou (correspondant partiel) P>

select id, count(char) AS count from chartable where (char = x or char = y or char = z ...) group by id order by count;


0 commentaires

2
votes

Cela pourrait être un début, sauf que cela ne vérifie pas si nous avons suffisamment de lettres, uniquement s'il a les bonnes lettres.

WITH words AS 
(SELECT word, substring(word,s,1) as sub from
(select word,generate_series(1,length(word)) as s from 
(
  SELECT word from
(select word,generate_series(1,length(word)) as s from good_words) as q
GROUP BY word
HAVING array_agg(substring(word,s,1)) <@ ARRAY['t','e','s','e','r','e','r','o','r','e','m','a','s','d','s','s']
)as q) as q)
SELECT DISTINCT w.word FROM
(
SELECT word,words.sub,count(DISTINCT s) as cnt FROM
(SELECT s, substring(array_to_string(l, ''),s,1) as sub FROM
(SELECT l, generate_subscripts(l,1) as s FROM 
 (SELECT ARRAY['t','e','s','e','r','e','r','o','r','e','m','a','s','d','s','s'] as l) 
 as q) 
as q) as let JOIN
words ON let.sub=words.sub
GROUP BY words.word,words.sub) as let
JOIN
(select word,sub,count(*) as cnt from words
 GROUP BY word, sub)
as w ON let.word=w.word AND let.sub=w.sub AND let.cnt>=w.cnt
GROUP BY w.word
HAVING sum(w.cnt)=length(w.word) ORDER BY w.word;


2 commentaires

Wow, essayant de comprendre cela en testant des extraits dans le violon SQL ... L'instruction SQL avec des mots comme (Sélectionnez ....) - Cela crée-t-il une table temporaire appelée mots ? Et l'utilise dans un rejoindre ?


@Alexandrefarber Oui, il fait. C'est un CTE ( Postgresql.org/docs/8.4/static/queries- avec.html ).



4
votes

Nice question, j'ai suscité.

Qu'est-ce que vous êtes à la hauteur, c'est une liste de toutes les permutations possibles des lettres données d'une longueur donnée. Comme décrit dans le PostgreSQL Wiki , vous pouvez créer une fonction et l'appeler comme ceci (correspond aux lettres en surbrillance Dans votre capture d'écran): p> xxx pré>

maintenant, pour interroger le Good_words code> Utilisez quelque chose comme: p>

SELECT gw.word, gw.stamp
  FROM good_words gw
  JOIN permute('{E,R,O,M}'::text[]) s(w) ON gw.word=array_to_string(s.w, '');


1 commentaires

Comme une jointure avec une temp. Table générée par ce procéder? Bonne idée! Cependant, je pense qu'il est préférable d'avoir la liste de bons mots comme Origine Vs. générant une liste de toutes les permutations de toutes lettres possibles - dont beaucoup ne seront pas des mots valides ...



1
votes

ne fonctionne pas dans 8.4. Probablement 9.1+ seulement. SQL FIDELLE

select word
from (
    select unnest(string_to_array(word, null)) c, word from good_words
    intersect all
    select unnest(string_to_array('TESTREROREMASDSS', null)) c, word from good_words
) s
group by word
having
    array_agg(c order by c) = 
    (select array_agg(c order by c) from unnest(string_to_array(word, null)) a(c))


2 commentaires

Le violon manquant: sqlfiddle.com/#!12/b9764/1 le Quatrième bouton VOUS CHANGEZ DELIMITER afin que cela ne s'engage pas sur le point-virgule (mais tout en tapissant dans une ligne fonctionne aussi)


@Jakub merci. Le corrigé pour 8.4



1
votes

Vous pouvez ajouter la colonne avec des lettres SORTERD formatées comme '% A% C% T%'. Ensuite, utilisez la requête: xxx

pour trouver des mots pouvant être construits à partir de lettres 'Abcttx'. Je ne sais pas sur la performance, mais la simplicité ne peut probablement pas être battu :)


5 commentaires

Il attraperait acte mais pas CTA . Essayez Sélectionnez 'Abctx' comme '% C% T% A%'


@Clodoaldoneto Oui, c'est pourquoi vous devez trier les lettres avant de les stocker dans la colonne (afin de ne jamais stocker '% C% T% A' Là). Aussi les lettres de la requête doivent être triées


C'est très simple lorsque le mot est déjà trié. Avez-vous essayé de trier une chaîne en 8.4? Et insérer le % ? J'ai essayé et j'ai dû construire une fonction de PLPGSQL non triviale.


@Clodoaldoneto un petit piratage: Sélectionnez '%' || Array_to_string (tableau (Sélectionnez Regexp_split_to_Table ('Cat', '. *?') Commander par 1), '%') || '%'


Vous devriez inclure cela dans votre réponse car le OP ne peut probablement pas le comprendre. À propos de la performance La seule chose que je peux deviner est qu'un comme d'expression commençant par un % est mauvais. Seul l'OP peut compenser tout cela. Je fais tous ces commentaires sur votre réponse juste parce que cela a attiré mon attention et je l'aime beaucoup. Je ne votons tout simplement pas comme ma politique de ne pas voter sur les réponses où j'ai également répondu.



1
votes

Voici une requête qui trouve les réponses qui peuvent être trouvées en parcourant des champs adjacents.

with recursive
input as (select '{{"t","e","s","e"},{"r","e","r","o"},{"r","e","m","a"},{"s","d","s","s"}}'::text[] as inp),
dxdy as(select * from (values(-1,-1),(-1,0),(-1,1),(0,1),(0,-1),(1,-1),(1,0),(1,1)) as v(dx, dy)),
start_position as(select * from generate_series(1,4) x, generate_series(1,4) y),
work as(select x,y,inp[y][x] as word from start_position, input
union
select w.x + dx, w.y + dy, w.word || inp[w.y+dy][w.x+dx]   
   from dxdy cross join input cross join work w 
   inner join good_words gw on gw.word like w.word || '%'
)
select distinct word from work
where exists(select * from good_words gw where gw.word = work.word)


2 commentaires

+1 Merci! Mais je pense que cela a le même problème que la suggestion de Vyegorov: vous générez d'abord toutes les combinaisons de lettre possibles (qui sont beaucoup, en particulier pour les plus grandes cartes - et beaucoup d'entre eux ne sont pas valides), puis correspondent au Good_words . Il me semble plus efficace de commencer à partir de l'autre extrémité: passer par le Good_words et (en quelque sorte, qui fait l'objet de ma question) essayez de faire correspondre les lettres du tableau.


Remarque Il y a une taille dans la mesure où elle élimine les mots générés pour lesquels il n'y a pas de préfixe dans Good_words. Mais je viens de l'essayer sur une liste de mots réelle et c'est très lent, alors pas vraiment utilisable. Voir mon autre réponse :)



0
votes

Ma propre solution consiste à créer Un déclencheur d'insertion , qui écrit des fréquences de lettre dans une colonne de matrice: xxx

puis je génère une matrice similaire pour la chaîne de carte aléatoire Tesereroremasss et comparez les deux tableaux à l'aide du Array contient opérateur @ >

Toutes les nouvelles idées ou améliorations sont toujours les bienvenues!


0 commentaires