[letor] Update for changes to str()
[xapian.git] / xapian-core / docs / facets.rst
blob10a8a7f5fd33ed205e632dcc1178d328565b39be
2 .. Copyright (C) 2007,2010,2011 Olly Betts
3 .. Copyright (C) 2009 Lemur Consulting Ltd
4 .. Copyright (C) 2011 Richard Boulton
6 =======================
7 Xapian Faceting Support
8 =======================
10 .. contents:: Table of contents
12 Introduction
13 ============
15 Xapian provides functionality which allows you to dynamically generate complete
16 lists of category values which feature in matching documents.  There are
17 numerous potential uses this can be put to, but a common one is to offer the
18 user the ability to narrow down their search by filtering it to only include
19 documents with a particular value of a particular category.  This is often
20 referred to as ``faceted search``.
22 You may have many multiple facets (for example colour, manufacturer, product
23 type) so Xapian allows you to handle multiple facets at once.
25 How to use Faceting
26 ===================
28 Indexing
29 --------
31 When indexing a document, you need to add each facet in a different numbered
32 value slot.  As described elsewhere in the documentation, each Xapian document
33 has a set of "value slots", each of which is addressed by a number, and can
34 contain a value which is an arbitrary string.
36 The ``Xapian::Document::add_value()`` method can be used to put values into a
37 particular slot.  So, if you had a database of books, you might put "price"
38 facet values in slot 0, say (serialised to strings using
39 ``Xapian::sortable_serialise``, or some similar function), "author" facet
40 values in slot 1, "publisher" facet values in slot 2 and "publication type"
41 (eg, hardback, softback, etc) values in slot 3.
43 Searching
44 ---------
46 Finding Facets
47 ~~~~~~~~~~~~~~
49 At search time, for each facet you want to consider, you need to get a count of
50 the number of times each facet value occurs in each slot; for the example
51 above, if you wanted to get facets for "price", "author" and "publication type"
52 you'd want to get the counts from slots 0, 1 and 3.
54 This can be done by calling ``Xapian::Enquire::add_matchspy()`` with a pointer
55 to a ``Xapian::ValueCountMatchSpy`` object for each value slot you want to
56 get facet counts for, like so::
58     Xapian::ValueCountMatchSpy spy0(0);
59     Xapian::ValueCountMatchSpy spy1(1);
60     Xapian::ValueCountMatchSpy spy3(3);
62     Xapian::Enquire enq(db);
63     enq.add_matchspy(&spy0);
64     enq.add_matchspy(&spy1);
65     enq.add_matchspy(&spy3);
67     enq.set_query(query);
69     Xapian::MSet mset = enq.get_mset(0, 10, 10000);
71 The ``10000`` in the call to ``get_mset()`` tells Xapian to check at least
72 10000 documents, so the MatchSpy objects will be passed at least 10000
73 documents to tally facet information from (unless fewer than 10000 documents
74 match the query, in which case they will see all of them).  Setting this to
75 ``db.get_doccount()`` will make the facet counts exact, but Xapian will have to
76 do more work for most queries so searches will be slower.
78 The ``spy`` objects now contain the facet information.  You can find out how
79 many documents they looked at by calling ``spy0.get_total()``.  (All the spies
80 will have looked at the same number of documents.)  You can read the values
81 from, say, ``spy0`` like this::
83     Xapian::TermIterator i;
84     for (i = spy0.values_begin(); i != spy0.values_end(); ++i) {
85         cout << *i << ": " << i.get_termfreq() << endl;
86     }
88 Restricting by Facet Values
89 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
91 If you're using the facets to offer the user choices for narrowing down
92 their search results, you then need to be able to apply a suitable filter.
94 For a single value, you could use ``Xapian::Query::OP_VALUE_RANGE`` with the
95 same start and end, or ``Xapian::MatchDecider``, but it's probably most
96 efficient to also index the categories as suitably prefixed boolean terms and
97 use those for filtering.