2015-03-22 8 views
9

Sto provando ad usare il tipo "newish" JSONB.Come indicizzare i valori interi di jsonb

Ho una tabella documents con un campo jsonb properties e in quello è un campo publication_year. Voglio trovare tutti i record di documenti entro un intervallo di un anno, ad es. 2013-2015. [MODIFICA: interrogare per un intervallo di valori è la sfida principale qui, anche se ho utilizzato un esempio di corrispondenza esatta di seguito. L'approccio richiesto si applicherebbe anche per, diciamo gamme di dollari (prezzo> $ 20 e il prezzo < $ 40) o intervalli timestamp)]

ho provato:.

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

ERROR: cannot cast type jsonb to integer 

così come:

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.` 

Ho visto da questo post http://www.postgresql.org/message-id/[email protected] che questo dovrebbe essere possibile, ma non riesco a capire la sintassi corretta.

Quando ho solo fare un indice semplice:

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

si crea un indice, ma non posso interrogare utilizzando valori interi per ottenere una gamma che va, si dice

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. 

Eventuali suggerimenti e suggerimenti molto apprezzati. Sono sicuro che anche gli altri ne trarranno beneficio. TIA

risposta

1

Perché non si fa a definire un indice per l'intera jsonb campo, as described in the doc?

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

Grazie. Penso che questa sia la risposta che stavo cercando. Anche se i documenti non lo specificano, con questa soluzione è possibile utilizzare CAST per ottenere i risultati dell'intervallo, come in: 'EXPLAIN ANALYZE SELECT COUNT (*) DA documenti WHERE cast (proprietà - >> 'publication_year' AS integer)> 2012 AND cast (properties - >> 'publication_year' AS integer) <2016; –

+0

Non sono sicuro, se utilizzarlo in questo modo avrà un impatto sulle prestazioni (che credo sia l'obiettivo). Secondo il doc - l'operatore "- >>" non è supportato da questo tipo di indice. Inoltre, puoi combinare 'x> A AND x murison

2

1) Non ci sono indici GIN per intero (almeno non fuori dalla scatola), utilizzare un btree.

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

2) L'errore è abbastanza auto-esplicativo, il cast del intero come testo o utilizzare il testo per il confronto:

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

Grazie, è utile, ma non affronta il mio problema principale: interrogare l'intervallo (forse avrei dovuto essere più esplicito). L'obiettivo finale è qualcosa come trovare tutti i record in cui 'publication_year' è> 2012 e <2016. –

+0

@WillKessler Puoi farlo con un indice b-tree. Hai provato? –

+0

Avevo provato, ma non ottenevo correttamente la query. Ma ora con il tuo aiuto e il mio omicidio, ce l'ho, vedi il commento sopra alla risposta di Murison. Grazie comunque per la vostra assistenza. –

1

È possibile eseguire il cast come numero intero e utilizzare l'estensione contrib/btree_gin.

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

Nella mia esperienza ho riscontrato che l'utilizzo degli indici GIN sulle colonne JSONB non era più veloce. Si può solo creare un indice normale per fusione in un numero intero

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

Inoltre, GIN ha qualche limitations che dovrebbe essere considerato prima di creare uno. Anche l'indicizzazione dell'intera colonna JSONB può comportare enormi indici di dimensioni tabella.

Questo è basato sulla mia esperienza e sulla documentazione di Postgres.