88 </indexterm>
99
1010 <para>
11- <literal>bloom</> is a module that implements an index access method. It comes
12- as an example of custom access methods and generic WAL record usage. But it
13- is also useful in itself.
11+ <literal>bloom</> provides an index access method based on
12+ <ulink url="http://en.wikipedia.org/wiki/Bloom_filter">Bloom filters</ulink>.
1413 </para>
1514
16- <sect2>
17- <title>Introduction</title>
15+ <para>
16+ A Bloom filter is a space-efficient data structure that is used to test
17+ whether an element is a member of a set. In the case of an index access
18+ method, it allows fast exclusion of non-matching tuples via signatures
19+ whose size is determined at index creation.
20+ </para>
1821
19- <para>
20- The implementation of a
21- <ulink url="http://en.wikipedia.org/wiki/Bloom_filter">Bloom filter</ulink>
22- allows fast exclusion of non-candidate tuples via signatures.
23- Since a signature is a lossy representation of all indexed attributes,
24- search results must be rechecked using heap information.
25- The user can specify signature length in bits (default 80, maximum 4096)
26- and the number of bits generated for each index column (default 2,
27- maximum 4095).
28- </para>
22+ <para>
23+ A signature is a lossy representation of the indexed attribute(s), and as
24+ such is prone to reporting false positives; that is, it may be reported
25+ that an element is in the set, when it is not. So index search results
26+ must always be rechecked using the actual attribute values from the heap
27+ entry. Larger signatures reduce the odds of a false positive and thus
28+ reduce the number of useless heap visits, but of course also make the index
29+ larger and hence slower to scan.
30+ </para>
2931
30- <para>
31- This index is useful if a table has many attributes and queries include
32- arbitrary combinations of them. A traditional <literal>btree</> index is
33- faster than a bloom index, but it can require many indexes to support all
34- possible queries where one needs only a single bloom index. A Bloom index
35- supports only equality comparison. Since it's a signature file, and not a
36- tree, it always must be read fully, but sequentially, so that index search
37- performance is constant and doesn't depend on a query.
38- </para>
39- </sect2>
32+ <para>
33+ This type of index is most useful when a table has many attributes and
34+ queries test arbitrary combinations of them. A traditional btree index is
35+ faster than a bloom index, but it can require many btree indexes to support
36+ all possible queries where one needs only a single bloom index. Note
37+ however that bloom indexes only support equality queries, whereas btree
38+ indexes can also perform inequality and range searches.
39+ </para>
4040
4141 <sect2>
4242 <title>Parameters</title>
4343
4444 <para>
45- <literal>bloom</> indexes accept the following parameters in the
46- <literal>WITH</>
47- clause.
45+ A <literal>bloom</> index accepts the following parameters in its
46+ <literal>WITH</> clause:
4847 </para>
4948
5049 <variablelist>
5150 <varlistentry>
5251 <term><literal>length</></term>
5352 <listitem>
5453 <para>
55- Length of signature in bits
54+ Length of each signature (index entry) in bits. The default
55+ is <literal>80</> bits and maximum is <literal>4096</>.
5656 </para>
5757 </listitem>
5858 </varlistentry>
6262 <term><literal>col1 — col32</></term>
6363 <listitem>
6464 <para>
65- Number of bits generated for each index column
65+ Number of bits generated for each index column. Each parameter's name
66+ refers to the number of the index column that it controls. The default
67+ is <literal>2</> bits and maximum is <literal>4095</>. Parameters for
68+ index columns not actually used are ignored.
6669 </para>
6770 </listitem>
6871 </varlistentry>
7376 <title>Examples</title>
7477
7578 <para>
76- An example of an index definition is given below.
79+ This is an example of creating a bloom index:
7780 </para>
7881
7982<programlisting>
@@ -82,92 +85,135 @@ CREATE INDEX bloomidx ON tbloom USING bloom (i1,i2,i3)
8285</programlisting>
8386
8487 <para>
85- Here, we created a bloom index with a signature length of 80 bits,
86- and attributes i1 and i2 mapped to 2 bits, and attribute i3 mapped to 4 bits.
88+ The index is created with a signature length of 80 bits, with attributes
89+ i1 and i2 mapped to 2 bits, and attribute i3 mapped to 4 bits. We could
90+ have omitted the <literal>length</>, <literal>col1</>,
91+ and <literal>col2</> specifications since those have the default values.
8792 </para>
8893
8994 <para>
90- Here is a fuller example of index definition and usage:
95+ Here is a more complete example of bloom index definition and usage, as
96+ well as a comparison with equivalent btree indexes. The bloom index is
97+ considerably smaller than the btree index, and can perform better.
9198 </para>
9299
93100<programlisting>
94- CREATE TABLE tbloom AS
95- SELECT
96- random()::int as i1,
97- random()::int as i2,
98- random()::int as i3,
99- random()::int as i4,
100- random()::int as i5,
101- random()::int as i6,
102- random()::int as i7,
103- random()::int as i8,
104- random()::int as i9,
105- random()::int as i10,
106- random()::int as i11,
107- random()::int as i12,
108- random()::int as i13
109- FROM
110- generate_series(1,1000);
111- CREATE INDEX bloomidx ON tbloom USING
112- bloom (i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12);
113- SELECT pg_relation_size('bloomidx');
114- CREATE index btree_idx ON tbloom(i1,i2,i3,i4,i5,i6,i7,i8,i9,i10,i11,i12);
115- SELECT pg_relation_size('btree_idx');
101+ =# CREATE TABLE tbloom AS
102+ SELECT
103+ (random() * 1000000)::int as i1,
104+ (random() * 1000000)::int as i2,
105+ (random() * 1000000)::int as i3,
106+ (random() * 1000000)::int as i4,
107+ (random() * 1000000)::int as i5,
108+ (random() * 1000000)::int as i6
109+ FROM
110+ generate_series(1,10000000);
111+ SELECT 10000000
112+ =# CREATE INDEX bloomidx ON tbloom USING bloom (i1, i2, i3, i4, i5, i6);
113+ CREATE INDEX
114+ =# SELECT pg_size_pretty(pg_relation_size('bloomidx'));
115+ pg_size_pretty
116+ ----------------
117+ 153 MB
118+ (1 row)
119+ =# CREATE index btreeidx ON tbloom (i1, i2, i3, i4, i5, i6);
120+ CREATE INDEX
121+ =# SELECT pg_size_pretty(pg_relation_size('btreeidx'));
122+ pg_size_pretty
123+ ----------------
124+ 387 MB
125+ (1 row)
116126</programlisting>
117127
128+ <para>
129+ A sequential scan over this large table takes a long time:
118130<programlisting>
119- =# EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 20 AND i10 = 15 ;
120- QUERY PLAN
121- -----------------------------------------------------------------------------------------------------------------
122- Bitmap Heap Scan on tbloom (cost=1.50..5.52 rows=1 width=52 ) (actual time=0.057..0.057 rows=0 loops=1)
123- Recheck Cond : ((i2 = 20 ) AND (i10 = 15 ))
124- -> Bitmap Index Scan on bloomidx (cost=0.00..1.50 rows=1 width=0) (actual time=0.041..0.041 rows=9 loops=1)
125- Index Cond: ((i2 = 20) AND (i10 = 15))
126- Total runtime: 0.081 ms
131+ =# EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451 ;
132+ QUERY PLAN
133+ ------------------------------------------------------------------------------------------------------------
134+ Seq Scan on tbloom (cost=0.00..213694.08 rows=1 width=24 ) (actual time=1445.438..1445.438 rows=0 loops=1)
135+ Filter : ((i2 = 898732 ) AND (i5 = 123451 ))
136+ Rows Removed by Filter: 10000000
137+ Planning time: 0.177 ms
138+ Execution time: 1445.473 ms
127139(5 rows)
128140</programlisting>
141+ </para>
129142
130143 <para>
131- Seqscan is slow.
144+ So the planner will usually select an index scan if possible.
145+ With a btree index, we get results like this:
146+ <programlisting>
147+ =# EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451;
148+ QUERY PLAN
149+ --------------------------------------------------------------------------------------------------------------------------------
150+ Index Only Scan using btreeidx on tbloom (cost=0.56..298311.96 rows=1 width=24) (actual time=445.709..445.709 rows=0 loops=1)
151+ Index Cond: ((i2 = 898732) AND (i5 = 123451))
152+ Heap Fetches: 0
153+ Planning time: 0.193 ms
154+ Execution time: 445.770 ms
155+ (5 rows)
156+ </programlisting>
132157 </para>
133158
159+ <para>
160+ Bloom is better than btree in handling this type of search:
134161<programlisting>
135- =# SET enable_bitmapscan = off;
136- =# SET enable_indexscan = off;
137- =# EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 20 AND i10 = 15;
138- QUERY PLAN
139- --------------------------------------------------------------------------------------------------
140- Seq Scan on tbloom (cost=0.00..25.00 rows=1 width=52) (actual time=0.162..0.162 rows=0 loops=1)
141- Filter: ((i2 = 20) AND (i10 = 15))
142- Total runtime: 0.181 ms
143- (3 rows)
162+ =# EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451;
163+ QUERY PLAN
164+ ---------------------------------------------------------------------------------------------------------------------------
165+ Bitmap Heap Scan on tbloom (cost=178435.39..178439.41 rows=1 width=24) (actual time=76.698..76.698 rows=0 loops=1)
166+ Recheck Cond: ((i2 = 898732) AND (i5 = 123451))
167+ Rows Removed by Index Recheck: 2439
168+ Heap Blocks: exact=2408
169+ -> Bitmap Index Scan on bloomidx (cost=0.00..178435.39 rows=1 width=0) (actual time=72.455..72.455 rows=2439 loops=1)
170+ Index Cond: ((i2 = 898732) AND (i5 = 123451))
171+ Planning time: 0.475 ms
172+ Execution time: 76.778 ms
173+ (8 rows)
144174</programlisting>
175+ Note the relatively large number of false positives: 2439 rows were
176+ selected to be visited in the heap, but none actually matched the
177+ query. We could reduce that by specifying a larger signature length.
178+ In this example, creating the index with <literal>length=200</>
179+ reduced the number of false positives to 55; but it doubled the index size
180+ (to 306 MB) and ended up being slower for this query (125 ms overall).
181+ </para>
145182
146- <para>
147- A btree index will be not used for this query.
148- </para>
149-
183+ <para>
184+ Now, the main problem with the btree search is that btree is inefficient
185+ when the search conditions do not constrain the leading index column(s).
186+ A better strategy for btree is to create a separate index on each column.
187+ Then the planner will choose something like this:
150188<programlisting>
151- =# DROP INDEX bloomidx;
152- =# CREATE INDEX btree_idx ON tbloom(i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12);
153- =# EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 20 AND i10 = 15;
154- QUERY PLAN
155- --------------------------------------------------------------------------------------------------
156- Seq Scan on tbloom (cost=0.00..25.00 rows=1 width=52) (actual time=0.210..0.210 rows=0 loops=1)
157- Filter: ((i2 = 20) AND (i10 = 15))
158- Total runtime: 0.250 ms
159- (3 rows)
189+ =# EXPLAIN ANALYZE SELECT * FROM tbloom WHERE i2 = 898732 AND i5 = 123451;
190+ QUERY PLAN
191+ ------------------------------------------------------------------------------------------------------------------------------
192+ Bitmap Heap Scan on tbloom (cost=9.29..13.30 rows=1 width=24) (actual time=0.148..0.148 rows=0 loops=1)
193+ Recheck Cond: ((i5 = 123451) AND (i2 = 898732))
194+ -> BitmapAnd (cost=9.29..9.29 rows=1 width=0) (actual time=0.145..0.145 rows=0 loops=1)
195+ -> Bitmap Index Scan on tbloom_i5_idx (cost=0.00..4.52 rows=11 width=0) (actual time=0.089..0.089 rows=10 loops=1)
196+ Index Cond: (i5 = 123451)
197+ -> Bitmap Index Scan on tbloom_i2_idx (cost=0.00..4.52 rows=11 width=0) (actual time=0.048..0.048 rows=8 loops=1)
198+ Index Cond: (i2 = 898732)
199+ Planning time: 2.049 ms
200+ Execution time: 0.280 ms
201+ (9 rows)
160202</programlisting>
203+ Although this query runs much faster than with either of the single
204+ indexes, we pay a large penalty in index size. Each of the single-column
205+ btree indexes occupies 214 MB, so the total space needed is over 1.2GB,
206+ more than 8 times the space used by the bloom index.
207+ </para>
161208 </sect2>
162209
163210 <sect2>
164- <title>Opclass interface </title>
211+ <title>Operator Class Interface </title>
165212
166213 <para>
167- The Bloom opclass interface is simple. It requires 1 supporting function:
168- a hash function for the indexing datatype. It provides 1 search operator:
169- the equality operator. The example below shows <literal>opclass</>
170- definition for <literal>text</> datatype.
214+ An operator class for bloom indexes requires only a hash function for the
215+ indexed datatype and an equality operator for searching. This example
216+ shows the opclass definition for the <type>text</> data type:
171217 </para>
172218
173219<programlisting>
@@ -179,22 +225,21 @@ DEFAULT FOR TYPE text USING bloom AS
179225 </sect2>
180226
181227 <sect2>
182- <title>Limitation </title>
228+ <title>Limitations </title>
183229 <para>
184-
185230 <itemizedlist>
186231 <listitem>
187232 <para>
188- For now, only opclasses for <literal >int4</>, <literal >text</> come
189- with the module. However, users may define more of them .
233+ Only operator classes for <type >int4</> and <type >text</> are
234+ included with the module.
190235 </para>
191236 </listitem>
192237
193238 <listitem>
194239 <para>
195- Only the <literal>=</literal> operator is supported for search at the
196- moment. But it's possible to add support for arrays with contains and
197- intersection operations in the future.
240+ Only the <literal>=</literal> operator is supported for search. But
241+ it is possible to add support for arrays with union and intersection
242+ operations in the future.
198243 </para>
199244 </listitem>
200245 </itemizedlist>
0 commit comments