2015-03-22 9 views
9

Ich versuche, den "neuen" JSONB-Typ zu verwenden.Wie jsonb Integer-Werte indexieren

Ich habe eine documents Tabelle mit einem properties jsonb Feld, und in diesem ist ein Feld publication_year. Ich möchte alle Dokumente innerhalb eines Jahres z. 2013-2015. [BEARBEITEN: Die Abfrage nach einer Reihe von Werten ist die größte Herausforderung, auch wenn ich unten ein genau passendes Beispiel verwendet habe. Der angeforderte Ansatz würde auch für, sagen Dollar Bereiche (Preis> $ 20 und Preis < 40 $) oder Zeitstempel Bereiche)]

ich versucht habe.

create index test1 on documents using gin ((cast(properties->'announced_on_year' as integer))); 

ERROR: cannot cast type jsonb to integer 

sowie:

create index test1 on documents using gin (cast(properties->>'publication_year' as integer)); 

ERROR: data type integer has no default operator class for access method "gin" 
HINT: You must specify an operator class for the index or define a default operator class for the data type.` 

Ich sah von diesem Beitrag http://www.postgresql.org/message-id/[email protected], dass dies möglich sein sollte, aber ich kann nicht die richtige Syntax herausfinden.

Wenn ich nur einen einfachen Index tun:

create index test1 on documents using gin ((properties->'publication_year')); 

ein Index erstellt wird, aber ich kann es nicht abfragen Integer-Werte mit einem Bereich in Gang zu bringen, heißt es

select count(*) from documents where properties->>'publication_year' = 2015; 
ERROR: operator does not exist: text = integer 
LINE 1: ...*) from documents where properties->>'publication_year' = 2015; 
          ^
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts. 

Irgendwelche Tipps und Hinweise sehr geschätzt. Ich bin sicher, dass auch andere davon profitieren werden. TIA

Antwort

1

Warum Sie nicht über einen Index für den gesamten jsonb definieren Feld, as described in the doc?

create index test1 on documents using gin (properties); 
+0

Danke-- Ich denke, das ist die Antwort, die ich suchte. Auch wenn die Dokumente dies nicht angeben, können Sie mit dieser Lösung CAST verwenden, um Bereichsresultate zu erhalten, wie in: 'EXPLAIN ANALYSE SELECT COUNT (*) FROM Dokumente WHERE Cast (Eigenschaften - >> 'publication_year' AS integer)> 2012 AND cast (Eigenschaften - >> 'publication_year' AS integer) <2016; –

+0

Ich bin mir nicht sicher, ob dieser Weg sich auf die Performance auswirkt (was ich denke, ist das Ziel). Laut dem Dokument wird der Operator "- >>" von diesem Indextyp nicht unterstützt. Außerdem können Sie 'x> A UND x murison

2

1) Es gibt keine GIN-Indizes für Integer (zumindest nicht out of the box), verwenden Sie einen btree.

create index test1 on documents using btree (cast (properties->>'announced_on_year' as int)); 

2) Der Fehler ist ziemlich selbsterklärend, warf die ganze Zahl als Text oder verwenden, um Text für den Vergleich:

select count(*) from documents where properties->>'publication_year' = '2015'; 
+0

Danke, das ist hilfreich, aber es adressiert nicht mein Hauptproblem: Bereichsabfrage (vielleicht hätte ich expliziter sein sollen). Das Endziel ist so etwas wie alle Datensätze zu finden, bei denen 'publication_year'> 2012 und <2016 ist. –

+0

@WillKessler Das geht mit einem b-tree-Index. Hast du es versucht? –

+0

Ich hatte es versucht, bekam aber die Anfrage nicht richtig. Aber jetzt mit deiner Hilfe und Murion, ich habe es, siehe den Kommentar oben zu Murisons Antwort. Vielen Dank für Ihre Hilfe. –

1

Sie können als Ganzzahl umwandeln und die Erweiterung contrib/btree_gin verwenden.

create extension btree_gin; 
create index tt_jb_int_idx on tt using gin(cast (jb->>'price' as int)); 
explain analyze select * from tt where cast(jb->>'price' as int) > 3 and cast(jb->>'price' as int) > 'price'::text))::integer > 3) AND (((jb ->> 'price'::text))::integer Bitmap Index Scan on tt_jb_int_idx (cost=0.00..28.06 rows=6 width=0) (actual time=0.016..0.016 rows=1 loops=1) 
     Index Cond: ((((jb ->> 'price'::text))::integer > 3) AND (((jb ->> 'price'::text))::integer
2

Ich habe in meinen Erfahrungen festgestellt, dass die Verwendung von GIN-Indizes auf JSONB-Spalten nicht schneller war. Sie können nur einen normalen Index erstellen, indem es auf eine ganze Zahl

CREATE INDEX test1 ON documents ((properties->>'publication_year')::int); 

Auch Gießen, GIN einige limitations hat, die vor dem Erstellen eines in Betracht gezogen werden sollte. Selbst das Indizieren der gesamten JSONB-Spalte kann zu massiven Indexen in Tabellengröße führen.

Dies basiert auf meiner Erfahrung und der Durchsicht der Postgres-Dokumentation.