it-swarm.com.de

GROUP BY und ORDER BY Problem

Ich habe zwei Tabellen wie diese:

CREATE TABLE cmap5 (
   name     varchar(2000),
   lexemes  tsquery
);

und

CREATE TABLE IF NOT EXISTS synonyms_all_gin_tsvcolumn (
   cid       int NOT NULL,  -- REFERENCES pubchem_compounds_index(cid)
   name      varchar(2000) NOT NULL,  
   synonym   varchar(2000) NOT NULL,
   tsv_syns  tsvector,
   PRIMARY KEY (cid, name, synonym)
);

Meine aktuelle Anfrage lautet:

SELECT s.cid, s.synonym, c.name, ts_rank(s.tsv_syns,c.lexemes,16) 
FROM synonyms_all_gin_tsvcolumn s, cmap5 c
WHERE c.lexemes @@ s.tsv_syns

Und die Ausgabe ist:

cid     |  synonym                              | name (query)              | rank
5474706 | 10-Methoxyharmalan                    | 10-methoxyharmalan        | 0.0901673
1416    | (+/-)12,13-EODE                       | 12,13-EODE                | 0.211562
5356421 | LEUKOTOXIN B (12,13-EODE)             | 12,13-EODE                | 0.211562
 180933 | 1,4-Chrysenequinone                   | 1,4-chrysenequinone       | 0.211562
5283035 | 15-Deoxy-delta-12,14-prostaglandin J2 | 15-delta prostaglandin J2 | 0.304975
5311211 | 15-deoxy-delta 12 14-prostaglandin J2 | 15-delta prostaglandin J2 | 0.304975
5311211 | 15-deoxy-Delta(12,14)-prostaglandin J2| 15-delta prostaglandin J2 | 0.304975
5311211 | 15-Deoxy-delta-12,14-prostaglandin J2 | 15-delta prostaglandin J2 | 0.304975
5311211 | 15-Deoxy-delta 12, 14-Prostaglandin J2| 15-delta prostaglandin J2 | 0.304975

Ich möchte die Namensübereinstimmungen aller Zeilen in cmap5 In meiner Haupttabelle zurückgeben, die nach der Funktion ts_rank() geordnet sind, aber für jede Zeile in cmap5 Möchte ich:

  • wählen Sie für jede Abfrage nur die besten X cids aus (group by cid).
  • oder ORDER BY my results as 1+ts_rank/count(cid)

Um die beste Übereinstimmung zu erzielen, habe ich versucht, select distinct on c.name Hinzuzufügen, aber wenn der Rang gleich ist, möchte ich das cid mit mehr Übereinstimmungen zur Abfrage erhalten. Ich habe versucht, am Ende der Abfrage eine einfache Gruppe hinzuzufügen, aber ich erhalte eine Fehlermeldung. Wie kann ich das tun?

Kommentare hinzugefügt:

Einerseits für diejenigen Ergebnisse, deren Rang gleich ist, z. Über 5283035 und 5311211 erhalten Sie 5311211 als Top-Ergebnis, da dieses cid mehr Treffer als 5283035 hat, also möchte ich es irgendwie Berücksichtigen Sie die Anzahl der Treffer/cid im Rang, wie final_rank = 1 + ts_rank (cid)/no. von Treffern (cid).

Andererseits möchte ich die ersten X cids pro Abfragenamen erhalten. Wenn ich LIMIT X Verwende, werden die ersten X Ergebnisse der gesamten Abfragetabelle zurückgegeben, nicht die ersten Xpro Name (Zeile) der Abfrage Tisch wie ich will.

6
mcasfrox

Zunächst einmal scheint Ihr PRIMARY KEY, Der sich über zwei varchar(2000) Spalten erstreckt, extrem teuer zu sein. Wenn Sie Ihre PK für etwas anderes verwenden, schlage ich eine Ersatz-PK vor (verwenden Sie eine serial-Spalte ) und fügen Sie eine UNIQUE -Einschränkung hinzu, um die Eindeutigkeit von (cid, name, synonym).

Wenn eine Ihrer varchar -Spalten tatsächlich die maximale Länge verwendet, würden Sie die maximale Größe für einen Indexeintrag überschreiten. Sehen:

Ich rate was du willst ist das, weil es Sinn machen würde:

SELECT DISTINCT ON (c.name)
       c.name, min(s.synonym) AS min_synonym, s.cid
     , ts_rank(s.tsv_syns, c.lexemes, 16) AS rnk
     , count(*) AS ct
FROM   synonyms_all_gin_tsvcolumn s
JOIN   cmap5                      c ON c.lexemes @@ s.tsv_syns
GROUP  BY c.name, rnk, s.cid
ORDER  BY c.name, rnk DESC, ct DESC;
  • Ich verwende explizite [INNER] JOIN Mit angehängter Join-Bedingung, die Ihre CROSS JOIN Plus WHERE -Klausel ersetzt. Es wird allgemein als überlegen angesehen (einfacher zu lesen und zu debuggen). Ich benutze auch rnk als Spaltennamen, um den Grundfunktionsnamen rank als Bezeichner zu vermeiden.

  • Gruppieren Sie die Ergebnisse nach c.name, Die dasselbe rnk und s.cid Haben, nehmen Sie min(s.synonym) (mangels Definition in der Frage) und count(*) die Peers pro Gruppe.

  • Reduzieren Sie mit c.name (Postgres-spezifische Erweiterung des SQL-Standards DISTINCT) auf eine Zeile pro DISTINCT ON, Wobei der höchste Rang zuerst und innerhalb desselben Ranges die höchste Peer-Anzahl erreicht wird. Sehen:

  • Erste Zeile in jeder GROUP BY-Gruppe auswählen?

Das Kombinieren von GROUP BY Und DISTINCT ON Auf diese Weise in einer Abfrageebene ist möglich, da DISTINCT oder DISTINCT ON Angewendet werden afterGROUP BY.

9