@@ -220,13 +220,14 @@ for more examples.
220220GIN indexes
221221-----------
222222
223- JsQuery extension contains two operator classes (opclasses) for GIN which
223+ JsQuery extension contains three operator classes (opclasses) for GIN which
224224provide different kinds of query optimization.
225225
226226 * ` jsonb_path_value_ops `
227+ * ` jsonb_laxpath_value_ops `
227228 * ` jsonb_value_path_ops `
228229
229- In each of two GIN opclasses jsonb documents are decomposed into entries. Each
230+ In each of GIN opclasses jsonb documents are decomposed into entries. Each
230231entry is associated with particular value and it's path. Difference between
231232opclasses is in the entry representation, comparison and usage for search
232233optimization.
@@ -247,7 +248,7 @@ same `#` sign in the path.
247248
248249Major problem in the entries representation is its size. In the given example
249250key "a" is presented three times. In the large branchy documents with long
250- keys size of naive entries representation becomes unreasonable. Both opclasses
251+ keys size of naive entries representation becomes unreasonable. All opclasses
251252address this issue but in a slightly different way.
252253
253254### ` jsonb_path_value_ops `
@@ -263,6 +264,21 @@ is hashed and it is higher part of entry we need to know the full path to
263264the value in order to use it for search. However, once path is specified
264265we can use both exact and range searches very efficiently.
265266
267+ ### ` jsonb_laxpath_value_ops `
268+
269+ ` jsonb_laxpath_value_ops ` differs from the ` jsonb_path_value_ops ` only in
270+ that it skips array path items from the hashing. So, the jsonb document above
271+ would be decomposed into following entries:
272+
273+ * ` (hash("a", "b"); "xyz") `
274+ * ` (hash("a", "c"); true) `
275+ * ` (hash("a"); 10) `
276+ * ` (hash("d", "e"); 7) `
277+ * ` (hash("d", "e"); false) `
278+
279+ Skipping array items greatly simplifies extraction of lax JSON path queries –
280+ there is no need to extract all possible unwrapped paths (see example for
281+ ` gin_debug_jsonpath_path_value() ` below).
266282
267283### ` jsonb_value_path_ops `
268284
@@ -287,8 +303,15 @@ Unfortunately, opclasses aren't allowed to do any custom output to the
287303EXPLAIN. That's why JsQuery provides following functions which allows to see
288304how particular opclass optimizes given query.
289305
290- * gin\_ debug\_ query\_ path\_ value(jsquery) – for jsonb\_ path\_ value\_ ops
291- * gin\_ debug\_ query\_ value\_ path(jsquery) – for jsonb\_ value\_ path\_ ops
306+ * ` jsonb_path_value_ops ` :
307+ - ` gin_debug_query_path_value(jsquery) `
308+ - ` gin_debug_jsonpath_path_value(jsonpath) `
309+ * ` jsonb_laxpath_value_ops ` :
310+ - ` gin_debug_query_laxpath_value(jsquery) `
311+ - ` gin_debug_jsonpath_laxpath_value(jsonpath) `
312+ * ` jsonb_value_path_ops ` :
313+ - ` gin_debug_query_value_path(jsquery) `
314+ - ` gin_debug_jsonpath_value_path(jsonpath) `
292315
293316Result of these functions is a textual representation of query tree which
294317leafs are GIN search entries. Following examples show different results of
@@ -308,6 +331,31 @@ query optimization by different opclasses.
308331 *.y = 1 , entry 1 +
309332 y = 2 , entry 2 +
310333
334+ Examples for nearly equivalent JSON path query:
335+
336+ # SELECT gin_debug_jsonpath_value_path('$.x == 1 && ($.**.y == 1 || $.y == 2)');
337+ gin_debug_jsonpath_value_path
338+ -------------------------------
339+ AND +
340+ OR +
341+ *.y = 1 , entry 0 +
342+ y = 2 , entry 1 +
343+ x = 1 , entry 2 +
344+
345+ # SELECT gin_debug_jsonpath_path_value('$.x == 1 && ($.**.y == 1 || $.y == 2)');
346+ gin_debug_jsonpath_path_value
347+ -------------------------------
348+ OR +
349+ #.x = 1 , entry 0 +
350+ #.x.# = 1 , entry 1 +
351+ x = 1 , entry 2 +
352+ x.# = 1 , entry 3 +
353+
354+ # SELECT gin_debug_jsonpath_laxpath_value('$.x == 1 && ($.**.y == 1 || $.y == 2)');
355+ gin_debug_jsonpath_laxpath_value
356+ ----------------------------------
357+ x = 1 , entry 0 +
358+
311359Unfortunately, jsonb have no statistics yet. That's why JsQuery optimizer has
312360to do imperative decision while selecting conditions to be evaluated using
313361index. This decision is made by assumption that some condition types are less
0 commit comments