2015-03-22 20 views
9

Próbuję użyć "nowego" typu JSONB.Jak indeksować wartości całkowite jsonb

Mam tablicę documents z polem jsonb o rozmiarze properties, w tym polu publication_year. Chcę znaleźć wszystkie rekordy dokumentów w ciągu roku, np. 2013-2015. [EDYCJA: zapytanie o zakres wartości jest tutaj głównym wyzwaniem, mimo że użyłem przykładu dopasowania dokładnego poniżej. Żądana podejście byłoby również zastosowanie do, powiedzmy zakresy dolara (cena> $ 20 i cenę < 40 $) lub zakresy datownika)] ​​

próbowałem.

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

ERROR: cannot cast type jsonb to integer 

, jak:

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

Widziałem z tego wpisu http://www.postgresql.org/message-id/[email protected], że powinno to być możliwe, ale nie mogę znaleźć właściwej składni.

Kiedy tylko zrobić prosty indeks:

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

indeks jest tworzony, ale nie mogę zapytać go przy użyciu wartości całkowitych, aby uzyskać zakres dzieje, to mówi

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. 

Wszelkie wskazówki i wskazówki bardzo cenne. Jestem pewien, że inni też skorzystają. TIA

Odpowiedz

1

Dlaczego nie można określić indeks dla całego jsonb pole, as described in the doc?

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

Dziękuję - myślę, że to jest odpowiedź, której szukałem. Mimo że dokumenty nie określają tego, możesz za pomocą tego rozwiązania użyć CAST, aby uzyskać wyniki zasięgu, jak w: 'WYJAŚNIJ ANALIZĘ WYBIERZ COUNT (*) Z dokumentów WHERE obsada (właściwości - >> 'publication_year' AS integer)> 2012 I obsada (właściwości - >> 'publication_year' AS integer) <2016; –

+0

Nie jestem pewien, czy użycie go w ten sposób będzie miało wpływ na wydajność (co jest chyba celem). Według dokumentu - operator "- >>" nie jest obsługiwany przez ten typ indeksu. Również - możesz połączyć 'x> A AND x murison

2

1) Nie ma indeksów GIN dla liczby całkowitej (przynajmniej nie po wyjęciu z pudełka), użyj pliku btree.

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

2) Błąd jest dość oczywista, rzucić całkowitą jako tekst lub użyć tekstu dla porównania:

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

Dziękuję, to jest pomocne, ale nie rozwiązuje mojego głównego problemu: wyszukiwanie zakresu (być może powinienem być bardziej precyzyjny). Ostatecznym celem jest znalezienie wszystkich rekordów, w których 'publication_year' jest> 2012 i <2016. –

+0

@WillKessler Możesz to zrobić za pomocą indeksu b-tree. Czy próbowałeś? –

+0

Próbowałem, ale nie otrzymałem poprawnie zapytania. Ale teraz z twoją pomocą i murison, mam to, zobacz powyższy komentarz, aby odpowiedzieć na pytanie Murison. Dziękuję za pomoc. –

1

Możesz rzutować jako liczbę całkowitą i używać rozszerzenia 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

Znalazłem w moich doświadczeniach, że używanie indeksów GIN na kolumnach JSONB nie było szybsze. można po prostu stworzyć normalny indeks oddając ją do liczby całkowitej

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

Również GIN ma pewne limitations które należy rozważyć przed utworzeniem jednego. Nawet indeksowanie całej kolumny JSONB może spowodować powstanie ogromnych indeksów wielkości tabeli.

Jest to oparte na moim doświadczeniu i przejrzeniu dokumentacji Postgres.