+ url="http://www.dmoz.org">) is about 240 bytes.
+
- Example: 'Top.Countries.Europe.Russia'
+ Example: Top.Countries.Europe.Russia
+
- We introduce several datatypes:
+ The ltree> module provides several datatypes:
+
- ltree - is a datatype for label path.
-
-
-
- ltree[] - is a datatype for arrays of ltree.
+ ltree stores a label path.
+
- lquery
- - is a path expression that has regular expression in the label path and
- used for ltree matching. Star symbol (*) is used to specify any number of
- labels (levels) and could be used at the beginning and the end of lquery,
- for example, '*.Europe.*'.
+ lquery represents a regular-expression-like pattern
+ for matching ltree> values. A simple word matches that
+ label within a path. A star symbol (*>) matches zero
+ or more labels. For example:
+foo Match the exact label path foo>
+*.foo.* Match any label path containing the label foo>
+*.foo Match any label path whose last label is foo>
+
+
- The following quantifiers are recognized for '*' (like in Perl):
+ Star symbols can also be quantified to restrict how many labels
+ they can match:
+*{n>} Match exactly n> labels
+*{n>,} Match at least n> labels
+*{n>,m>} Match at least n> but not more than m> labels
+*{,m>} Match at most m> labels — same as *{0,m>}
+
-
-
-
{n} Match exactly n levels
-
-
-
{n,} Match at least n levels
-
-
-
{n,m} Match at least n but not more than m levels
-
-
-
{,m} Match at maximum m levels (eq. to {0,m})
-
-
+
- It is possible to use several modifiers at the end of a label:
+ There are several modifiers that can be put at the end of a non-star
+ label in lquery> to make it match more than just the exact match:
+@ Match case-insensitively, for example a@> matches A>
+* Match any label with this prefix, for example foo*> matches foobar>
+% Match initial underscore-separated words
+
+ The behavior of %> is a bit complicated. It tries to match
+ words rather than the entire label. For example
+ foo_bar%> matches foo_bar_baz> but not
+ foo_barbaz>. If combined with *>, prefix
+ matching applies to each word separately, for example
+ foo_bar%*> matches foo1_bar2_baz> but
+ not foo1_br2_baz>.
-
-
-
@ Do case-insensitive label matching
-
-
-
* Do prefix matching for a label
-
-
-
% Don't account word separator '_' in label matching, that is
- 'Russian%' would match 'Russian_nations', but not 'Russian'
-
-
-
-
+
- lquery can contain logical '!' (NOT) at the beginning
- of the label and '|' (OR) to specify possible alternatives for label
- matching.
-
- Example of lquery:
+ Also, you can write several possibly-modified labels separated with
+ |> (OR) to match any of those labels, and you can put
+ !> (NOT) at the start to match any label that doesn't
+ match any of the alternatives.
+
+ Here's an annotated example of lquery:
Top.*{0,2}.sport*@.!football|tennis.Russ*|Spain
- a) b) c) d) e)
+ a. b. c. d. e.
- A label path should
+ This query will match any label path that:
- begin from a node with label 'Top'
+ begins with the label Top
- and following zero or 2 labels until
+ and next has zero to two labels before
- a node with label beginning from case-insensitive prefix 'sport'
+ a label beginning with the case-insensitive prefix sport
- following node with label not matched 'football' or 'tennis' and
+ then a label not matching football nor
+ tennis
- end on node with label beginning from 'Russ' or strictly matched
- 'Spain'.
+ and then ends with a label beginning with Russ or
+ exactly matching Spain.
-
- - is a datatype for label searching (like type 'query' for full text
- searching, see contrib/tsearch). It's possible to use modifiers @,%,* at
- the end of word. The meaning of modifiers are the same as for lquery.
-
- Example: 'Europe & Russia*@ & !Transportation'
+
ltxtquery represents a full-text-search-like
+ pattern for matching ltree> values. An
+ ltxtquery value contains words, possibly with the
+ modifiers @>, *>, %> at the end;
+ the modifiers have the same meanings as in lquery>.
+ Words can be combined with &> (AND),
+ |> (OR), !> (NOT), and parentheses.
+ The key difference from
+ lquery> is that ltxtquery matches words without
+ regard to their position in the label path.
+
- Search paths contain words 'Europe' and 'Russia*' (case-insensitive) and
- not 'Transportation'. Notice, the order of words as they appear in label
- path is not important !
+ Here's an example ltxtquery:
+ Europe & Russia*@ & !Transportation
+
+ This will match paths that contain the label Europe and
+ any label beginning with Russia (case-insensitive),
+ but not paths containing the label Transportation.
+ The location of these words within the path is not important.
+ Also, when %> is used, the word can be matched to any
+ underscore-separated word within a label, regardless of position.
-
-
-
Operations
- The following operations are defined for type ltree:
+ Note: ltxtquery> allows whitespace between symbols, but
+ ltree> and lquery> do not.
+
+
+
+
Operators and Functions
-
-
- <,>,<=,>=,=, <>
- - Have their usual meanings. Comparison is doing in the order of direct
- tree traversing, children of a node are sorted lexicographic.
-
-
-
- ltree @> ltree
- - returns TRUE if left argument is an ancestor of right argument (or
- equal).
-
-
-
- ltree <@ ltree
- - returns TRUE if left argument is a descendant of right argument (or
- equal).
-
-
-
- ltree ~ lquery, lquery ~ ltree
- - return TRUE if node represented by ltree satisfies lquery.
-
-
-
- ltree ? lquery[], lquery ? ltree[]
- - return TRUE if node represented by ltree satisfies at least one lquery
- from array.
-
-
-
- ltree @ ltxtquery, ltxtquery @ ltree
- - return TRUE if node represented by ltree satisfies ltxtquery.
-
-
-
- ltree || ltree, ltree || text, text || ltree
- - return concatenated ltree.
-
-
-
-
- Operations for arrays of ltree (ltree[]):
+ Type ltree> has the usual comparison operators
+ =>, <>,
+ <>, >>, <=>, >=>.
+ Comparison sorts in the order of a tree traversal, with the children
+ of a node sorted by label text. In addition, there are the following
+ specialized operators:
-
-
- ltree[] @> ltree, ltree <@ ltree[]
- - returns TRUE if array ltree[] contains an ancestor of ltree.
-
-
-
- ltree @> ltree[], ltree[] <@ ltree
- - returns TRUE if array ltree[] contains a descendant of ltree.
-
-
-
- ltree[] ~ lquery, lquery ~ ltree[]
- - returns TRUE if array ltree[] contains label paths matched lquery.
-
-
-
- ltree[] ? lquery[], lquery[] ? ltree[]
- - returns TRUE if array ltree[] contains label paths matched atleaset one
- lquery from array.
-
-
-
- ltree[] @ ltxtquery, ltxtquery @ ltree[]
- - returns TRUE if array ltree[] contains label paths matched ltxtquery
- (full text search).
-
-
-
- ltree[] ?@> ltree, ltree ?<@ ltree[], ltree[] ?~ lquery, ltree[] ?@ ltxtquery
- - returns first element of array ltree[] satisfies corresponding condition
- and NULL in vice versa.
-
-
-
-
+
+
ltree> Operators
-
-
Remark
+
+
+ |
+ Operator
+ Returns
+ Description
+
+
+
+
+ |
+ ltree> @>> ltree>
+ boolean
+ is left argument an ancestor of right (or equal)?
+
+
+ |
+ ltree> <@> ltree>
+ boolean
+ is left argument a descendant of right (or equal)?
+
+
+ |
+ ltree> ~> lquery>
+ boolean
+ does ltree> match lquery>?
+
+
+ |
+ lquery> ~> ltree>
+ boolean
+ does ltree> match lquery>?
+
+
+ |
+ ltree> ?> lquery[]>
+ boolean
+ does ltree> match any lquery> in array?
+
+
+ |
+ lquery[]> ?> ltree>
+ boolean
+ does ltree> match any lquery> in array?
+
+
+ |
+ ltree> @> ltxtquery>
+ boolean
+ does ltree> match ltxtquery>?
+
+
+ |
+ ltxtquery> @> ltree>
+ boolean
+ does ltree> match ltxtquery>?
+
+
+ |
+ ltree> ||> ltree>
+ ltree
+ concatenate ltree> paths
+
+
+ |
+ ltree> ||> text>
+ ltree
+ convert text to ltree> and concatenate
+
+
+ |
+ text> ||> ltree>
+ ltree
+ convert text to ltree> and concatenate
+
+
+ |
+ ltree[]> @>> ltree>
+ boolean
+ does array contain an ancestor of ltree>?
+
+
+ |
+ ltree> <@> ltree[]>
+ boolean
+ does array contain an ancestor of ltree>?
+
+
+ |
+ ltree[]> <@> ltree>
+ boolean
+ does array contain a descendant of ltree>?
+
+
+ |
+ ltree> @>> ltree[]>
+ boolean
+ does array contain a descendant of ltree>?
+
+
+ |
+ ltree[]> ~> lquery>
+ boolean
+ does array contain any path matching lquery>?
+
+
+ |
+ lquery> ~> ltree[]>
+ boolean
+ does array contain any path matching lquery>?
+
+
+ |
+ ltree[]> ?> lquery[]>
+ boolean
+ does ltree> array contain any path matching any lquery>?
+
+
+ |
+ lquery[]> ?> ltree[]>
+ boolean
+ does ltree> array contain any path matching any lquery>?
+
+
+ |
+ ltree[]> @> ltxtquery>
+ boolean
+ does array contain any path matching ltxtquery>?
+
+
+ |
+ ltxtquery> @> ltree[]>
+ boolean
+ does array contain any path matching ltxtquery>?
+
+
+ |
+ ltree[]> ?@>> ltree>
+ ltree
+ first array entry that is an ancestor of ltree>; NULL if none
+
+
+ |
+ ltree[]> ?<@> ltree>
+ ltree
+ first array entry that is a descendant of ltree>; NULL if none
+
+
+ |
+ ltree[]> ?~> lquery>
+ ltree
+ first array entry that matches lquery>; NULL if none
+
+
+ |
+ ltree[]> ?@> ltxtquery>
+ ltree
+ first array entry that matches ltxtquery>; NULL if none
+
+
+
+
+
- Operations <@, @>, @ and
- ~ have analogues - ^<@, ^@>, ^@, ^~, which don't use
- indices!
+ The operators <@, @>,
+ @ and ~ have analogues
+ ^<@>, ^@>>, ^@>,
+ ^~, which are the same except they do not use
+ indexes. These are useful only for testing purposes.
+
+ The following functions are available:
+
+
+
+
ltree> Functions
+
+
+
+ |
+ Function
+ Return Type
+ Description
+ Example
+ Result
+
+
+
+
+ |
+ subltree(ltree, int start, int end)
+ ltree
+
subpath of ltree> from position start> to
+ position
end>-1 (counting from 0)
+ subltree('Top.Child1.Child2',1,2)
+ Child1
+
+
+ |
+ subpath(ltree, int offset, int len)
+ ltree
+ subpath of ltree> starting at position
+ If
offset> is negative, subpath starts that far from the
+ end of the path. If
len> is negative, leaves that many
+ labels off the end of the path.
+ subpath('Top.Child1.Child2',0,2)
+ Top.Child1
+
+
+ |
+ subpath(ltree, int offset)
+ ltree
+ subpath of ltree> starting at position
+
offset>, extending to end of path.
+ If
offset> is negative, subpath starts that far from the
+ end of the path.
+ subpath('Top.Child1.Child2',1)
+ Child1.Child2
+
+
+ |
+ nlevel(ltree)
+ integer
+ number of labels in path
+ nlevel('Top.Child1.Child2')
+ 3
+
+
+ |
+ index(ltree a, ltree b)
+ integer
+
position of first occurrence of b> in
+ index('0.1.2.3.5.4.5.6.8.5.6.8','5.6')
+ 6
+
+
+ |
+ index(ltree a, ltree b, int offset)
+ integer
+
position of first occurrence of b> in
+
a>, searching starting at offset>;
+ negative
offset> means start -offset>
+ labels from the end of the path
+ index('0.1.2.3.5.4.5.6.8.5.6.8','5.6',-4)
+ 9
+
+
+ |
+ text2ltree(text)
+ ltree
+ cast text> to ltree>
+
+
+
+
+ |
+ ltree2text(ltree)
+ text
+ cast ltree> to text>
+
+
+
+
+ |
+ lca(ltree, ltree, ...)
+ ltree
+ lowest common ancestor, i.e., longest common prefix of paths
+ (up to 8 arguments supported)
+ lca('1.2.2.3','1.2.3.4.5.6')
+ 1.2
+
+
+ |
+ lca(ltree[])
+ ltree
+ lowest common ancestor, i.e., longest common prefix of paths
+ lca(array['1.2.2.3'::ltree,'1.2.3'])
+ 1.2
+
+
+
+
+
-
Indices
+
Indexes
- Various indices could be created to speed up execution of operations:
+ ltree> supports several types of indexes that can speed
+ up the indicated operators:
- B-tree index over ltree: <, <=, =, >=, >
+ B-tree index over ltree>:
+ <>, <=>, =>,
+ >=>, >
- GiST index over ltree: <, <=, =, >=, >, @>, <@, @, ~, ?
+ GiST index over ltree>:
+ <>, <=>, =>,
+ >=>, >>,
+ @>>, <@>,
+ @>, ~>, ?
- Example:
+ Example of creating such an index:
CREATE INDEX path_gist_idx ON test USING GIST (path);
-
GiST index over ltree[]:
- ltree[]<@ ltree, ltree @> ltree[], @, ~, ?.
-
- Example:
+ GiST index over ltree[]>:
+ ltree[] <@ ltree>, ltree @> ltree[]>,
+ @>, ~>, ?
- CREATE INDEX path_gist_idx ON test USING GIST (array_path);
-
- Notices: This index is lossy.
-
-
-
-
-
-
-
Functions
-
-
-
- ltree subltree(ltree, start, end)
- returns subpath of ltree from start (inclusive) until the end.
+ Example of creating such an index:
- # select subltree('Top.Child1.Child2',1,2);
- subltree
- --------
- Child1
+ CREATE INDEX path_gist_idx ON test USING GIST (array_path);
-
-
- ltree subpath(ltree, OFFSET,LEN) and
- ltree subpath(ltree, OFFSET)
- returns subpath of ltree from OFFSET (inclusive) with length LEN.
- If OFFSET is negative returns subpath starts that far from the end
- of the path. If LENGTH is omitted, returns everything to the end
- of the path. If LENGTH is negative, leaves that many labels off
- the end of the path.
+ Note: This index type is lossy.
- # select subpath('Top.Child1.Child2',1,2);
- subpath
- -------
- Child1.Child2
-
- # select subpath('Top.Child1.Child2',-2,1);
- subpath
- ---------
- Child1
-
-
-
- int4 nlevel(ltree) - returns level of the node.
-
- # select nlevel('Top.Child1.Child2');
- nlevel
- --------
- 3
-
- Note, that arguments start, end, OFFSET, LEN have meaning of level of the
- node !
-
-
-
- int4 index(ltree,ltree) and
- int4 index(ltree,ltree,OFFSET)
- returns number of level of the first occurence of second argument in first
- one beginning from OFFSET. if OFFSET is negative, than search begins from |
- OFFSET| levels from the end of the path.
-
- SELECT index('0.1.2.3.5.4.5.6.8.5.6.8','5.6',3);
- index
- -------
- 6
- SELECT index('0.1.2.3.5.4.5.6.8.5.6.8','5.6',-4);
- index
- -------
- 9
-
-
-
- ltree text2ltree(text) and
- text ltree2text(text) cast functions for ltree and text.
-
-
-
- ltree lca(ltree,ltree,...) (up to 8 arguments) and
- ltree lca(ltree[]) Returns Lowest Common Ancestor (lca).
-
- # select lca('1.2.2.3','1.2.3.4.5.6');
- lca
- -----
- 1.2
- # select lca('{la.2.3,1.2.3.4.5.6}') is null;
- ?column?
- ----------
- f
-
-
-
Installation
- cd contrib/ltree
- make
- make install
- make installcheck
-
-
-
Example
+
+ This example uses the following data (also available in file
+ contrib/ltree/ltreetest.sql> in the source distribution):
+
+
- createdb ltreetest
- psql ltreetest < /usr/local/pgsql/share/contrib/ltree.sql
- psql ltreetest < ltreetest.sql
+CREATE TABLE test (path ltree);
+INSERT INTO test VALUES ('Top');
+INSERT INTO test VALUES ('Top.Science');
+INSERT INTO test VALUES ('Top.Science.Astronomy');
+INSERT INTO test VALUES ('Top.Science.Astronomy.Astrophysics');
+INSERT INTO test VALUES ('Top.Science.Astronomy.Cosmology');
+INSERT INTO test VALUES ('Top.Hobbies');
+INSERT INTO test VALUES ('Top.Hobbies.Amateurs_Astronomy');
+INSERT INTO test VALUES ('Top.Collections');
+INSERT INTO test VALUES ('Top.Collections.Pictures');
+INSERT INTO test VALUES ('Top.Collections.Pictures.Astronomy');
+INSERT INTO test VALUES ('Top.Collections.Pictures.Astronomy.Stars');
+INSERT INTO test VALUES ('Top.Collections.Pictures.Astronomy.Galaxies');
+INSERT INTO test VALUES ('Top.Collections.Pictures.Astronomy.Astronauts');
+CREATE INDEX path_gist_idx ON test USING gist(path);
+CREATE INDEX path_idx ON test USING btree(path);
-Now, we have a database ltreetest populated with a data describing hierarchy
-shown below:
+ Now, we have a table test> populated with data describing
+ the hierarchy shown below:
-
-
- TOP
- / | \
- Science Hobbies Collections
+ Top
+ / | \
+ Science Hobbies Collections
/ | \
Astronomy Amateurs_Astronomy Pictures
/ \ |
/ | \
Galaxies Stars Astronauts
+
- Inheritance:
+ We can do inheritance:
ltreetest=# select path from test where path <@ 'Top.Science';
- path
+ path
------------------------------------
Top.Science
Top.Science.Astronomy
Top.Science.Astronomy.Cosmology
(4 rows)
+
- Matching:
+ Here are some examples of path matching:
+
ltreetest=# select path from test where path ~ '*.Astronomy.*';
- path
+ path
-----------------------------------------------
Top.Science.Astronomy
Top.Science.Astronomy.Astrophysics
Top.Collections.Pictures.Astronomy.Galaxies
Top.Collections.Pictures.Astronomy.Astronauts
(7 rows)
+
ltreetest=# select path from test where path ~ '*.!pictures@.*.Astronomy.*';
- path
+ path
------------------------------------
Top.Science.Astronomy
Top.Science.Astronomy.Astrophysics
Top.Science.Astronomy.Cosmology
(3 rows)
+
- Full text search:
+ Here are some examples of full text search:
ltreetest=# select path from test where path @ 'Astro*% & !pictures@';
- path
+ path
------------------------------------
Top.Science.Astronomy
Top.Science.Astronomy.Astrophysics
(4 rows)
ltreetest=# select path from test where path @ 'Astro* & !pictures@';
- path
+ path
------------------------------------
Top.Science.Astronomy
Top.Science.Astronomy.Astrophysics
Top.Science.Astronomy.Cosmology
(3 rows)
+
- Using Functions:
+ Path construction using functions:
ltreetest=# select subpath(path,0,2)||'Space'||subpath(path,2) from test where path <@ 'Top.Science.Astronomy';
- ?column?
-------------------------------------------
- Top.Science.Space.Astronomy
- Top.Science.Space.Astronomy.Astrophysics
- Top.Science.Space.Astronomy.Cosmology
-(3 rows)
-We could create SQL-function:
-CREATE FUNCTION ins_label(ltree, int4, text) RETURNS ltree
-AS 'select subpath($1,0,$2) || $3 || subpath($1,$2);'
-LANGUAGE SQL IMMUTABLE;
-
- and previous select could be rewritten as:
-
-
-ltreetest=# select ins_label(path,2,'Space') from test where path <@ 'Top.Science.Astronomy';
- ins_label
+ ?column?
------------------------------------------
Top.Science.Space.Astronomy
Top.Science.Space.Astronomy.Astrophysics
- Or with another arguments:
+ We could simplify this by creating a SQL function that inserts a label
+ at a specified position in a path:
-
-CREATE FUNCTION ins_label(ltree, ltree, text) RETURNS ltree
-AS 'select subpath($1,0,nlevel($2)) || $3 || subpath($1,nlevel($2));'
+CREATE FUNCTION ins_label(ltree, int, text) RETURNS ltree
+AS 'select subpath($1,0,$2) || $3 || subpath($1,$2);'
LANGUAGE SQL IMMUTABLE;
-ltreetest=# select ins_label(path,'Top.Science'::ltree,'Space') from test where path <@ 'Top.Science.Astronomy';
- ins_label
+ltreetest=# select ins_label(path,2,'Space') from test where path <@ 'Top.Science.Astronomy';
+ ins_label
------------------------------------------
Top.Science.Space.Astronomy
Top.Science.Space.Astronomy.Astrophysics
-
-
Additional data
- To get more feeling from our ltree module you could download
- dmozltree-eng.sql.gz (about 3Mb tar.gz archive containing 300,274 nodes),
- available from
- dmozltree-eng.sql.gz, which is DMOZ catalogue, prepared for use with ltree.
- Setup your test database (dmoz), load ltree module and issue command:
-
- zcat dmozltree-eng.sql.gz| psql dmoz
-
- Data will be loaded into database dmoz and all indices will be created.
-
-
-
-
-
Benchmarks
- All runs were performed on my IBM ThinkPad T21 (256 MB RAM, 750Mhz) using DMOZ
- data, containing 300,274 nodes (see above for download link). We used some
- basic queries typical for walking through catalog.
-
-
-
-
Queries
-
-
- Q0: Count all rows (sort of base time for comparison)
-
- select count(*) from dmoz;
- count
- --------
- 300274
- (1 row)
-
-
-
- Q1: Get direct children (without inheritance)
-
- select path from dmoz where path ~ 'Top.Adult.Arts.Animation.*{1}';
- path
- -----------------------------------
- Top.Adult.Arts.Animation.Cartoons
- Top.Adult.Arts.Animation.Anime
- (2 rows)
-
-
-
- Q2: The same as Q1 but with counting of successors
-
- select path as parentpath , (select count(*)-1 from dmoz where path <@
- p.path) as count from dmoz p where path ~ 'Top.Adult.Arts.Animation.*{1}';
- parentpath | count
- -----------------------------------+-------
- Top.Adult.Arts.Animation.Cartoons | 2
- Top.Adult.Arts.Animation.Anime | 61
- (2 rows)
-
-
-
- Q3: Get all parents
-
- select path from dmoz where path @> 'Top.Adult.Arts.Animation' order by
- path asc;
- path
- --------------------------
- Top
- Top.Adult
- Top.Adult.Arts
- Top.Adult.Arts.Animation
- (4 rows)
-
-
-
- Q4: Get all parents with counting of children
-
- select path, (select count(*)-1 from dmoz where path <@ p.path) as count
- from dmoz p where path @> 'Top.Adult.Arts.Animation' order by path asc;
- path | count
- --------------------------+--------
- Top | 300273
- Top.Adult | 4913
- Top.Adult.Arts | 339
- Top.Adult.Arts.Animation | 65
- (4 rows)
-
-
-
- Q5: Get all children with levels
-
- select path, nlevel(path) - nlevel('Top.Adult.Arts.Animation') as level
- from dmoz where path ~ 'Top.Adult.Arts.Animation.*{1,2}' order by path asc;
- path | level
- ------------------------------------------------+-------
- Top.Adult.Arts.Animation.Anime | 1
- Top.Adult.Arts.Animation.Anime.Fan_Works | 2
- Top.Adult.Arts.Animation.Anime.Games | 2
- Top.Adult.Arts.Animation.Anime.Genres | 2
- Top.Adult.Arts.Animation.Anime.Image_Galleries | 2
- Top.Adult.Arts.Animation.Anime.Multimedia | 2
- Top.Adult.Arts.Animation.Anime.Resources | 2
- Top.Adult.Arts.Animation.Anime.Titles | 2
- Top.Adult.Arts.Animation.Cartoons | 1
- Top.Adult.Arts.Animation.Cartoons.AVS | 2
- Top.Adult.Arts.Animation.Cartoons.Members | 2
- (11 rows)
-
-
-
-
-
-
-
Timings
-+---------------------------------------------+
-|Query|Rows|Time (ms) index|Time (ms) no index|
-|-----+----+---------------+------------------|
-| Q0| 1| NA| 1453.44|
-|-----+----+---------------+------------------|
-| Q1| 2| 0.49| 1001.54|
-|-----+----+---------------+------------------|
-| Q2| 2| 1.48| 3009.39|
-|-----+----+---------------+------------------|
-| Q3| 4| 0.55| 906.98|
-|-----+----+---------------+------------------|
-| Q4| 4| 24385.07| 4951.91|
-|-----+----+---------------+------------------|
-| Q5| 11| 0.85| 1003.23|
-+---------------------------------------------+
-
- Timings without indices were obtained using operations which doesn't use
- indices (see above)
-
-
-
-
-
Remarks
- We didn't run full-scale tests, also we didn't present (yet) data for
- operations with arrays of ltree (ltree[]) and full text searching. We'll
- appreciate your input. So far, below some (rather obvious) results:
-
-
-
- Indices does help execution of queries
-
-
-
- Q4 performs bad because one needs to read almost all data from the HDD
-
-
-
-
-
-
-
Some Backgrounds
- The approach we use for ltree is much like one we used in our other GiST based
- contrib modules (intarray, tsearch, tree, btree_gist, rtree_gist). Theoretical
- background is available in papers referenced from our GiST development page
-
- A hierarchical data structure (tree) is a set of nodes. Each node has a
- signature (LPS) of a fixed size, which is a hashed label path of that node.
- Traversing a tree we could *certainly* prune branches if
-
- LQS (bitwise AND) LPS != LQS
-
- where LQS is a signature of lquery or ltxtquery, obtained in the same way as
- LPS.
-
- ltree[]:
-
- For array of ltree LPS is a bitwise OR-ed signatures of *ALL* children
- reachable from that node. Signatures are stored in RD-tree, implemented using
- GiST, which provides indexed access.
-
- ltree:
-
- For ltree we store LPS in a B-tree, implemented using GiST. Each node entry is
- represented by (left_bound, signature, right_bound), so that we could speedup
- operations <, <=, =, >=, > using left_bound, right_bound and prune branches of
- a tree using signature.
-
-
Authors
+
- additional information. Authors would like to thank Eugeny Rodichev for
+ additional information. Authors would like to thank Eugeny Rodichev for
helpful discussions. Comments and bug reports are welcome.
+