"Fossies" - the Fresh Open Source Software Archive

Member "xapian-core-1.4.14/docs/postingsource.html" (23 Nov 2019, 23149 Bytes) of package /linux/www/xapian-core-1.4.14.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) HTML source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file.

    1 <?xml version="1.0" encoding="utf-8" ?>
    2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    3 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    4 <head>
    5 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    6 <meta name="generator" content="Docutils 0.15.2: http://docutils.sourceforge.net/" />
    7 <title>Xapian::PostingSource</title>
    8 <style type="text/css">
    9 
   10 /*
   11 :Author: David Goodger (goodger@python.org)
   12 :Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
   13 :Copyright: This stylesheet has been placed in the public domain.
   14 
   15 Default cascading style sheet for the HTML output of Docutils.
   16 
   17 See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
   18 customize this style sheet.
   19 */
   20 
   21 /* used to remove borders from tables and images */
   22 .borderless, table.borderless td, table.borderless th {
   23   border: 0 }
   24 
   25 table.borderless td, table.borderless th {
   26   /* Override padding for "table.docutils td" with "! important".
   27      The right padding separates the table cells. */
   28   padding: 0 0.5em 0 0 ! important }
   29 
   30 .first {
   31   /* Override more specific margin styles with "! important". */
   32   margin-top: 0 ! important }
   33 
   34 .last, .with-subtitle {
   35   margin-bottom: 0 ! important }
   36 
   37 .hidden {
   38   display: none }
   39 
   40 .subscript {
   41   vertical-align: sub;
   42   font-size: smaller }
   43 
   44 .superscript {
   45   vertical-align: super;
   46   font-size: smaller }
   47 
   48 a.toc-backref {
   49   text-decoration: none ;
   50   color: black }
   51 
   52 blockquote.epigraph {
   53   margin: 2em 5em ; }
   54 
   55 dl.docutils dd {
   56   margin-bottom: 0.5em }
   57 
   58 object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
   59   overflow: hidden;
   60 }
   61 
   62 /* Uncomment (and remove this text!) to get bold-faced definition list terms
   63 dl.docutils dt {
   64   font-weight: bold }
   65 */
   66 
   67 div.abstract {
   68   margin: 2em 5em }
   69 
   70 div.abstract p.topic-title {
   71   font-weight: bold ;
   72   text-align: center }
   73 
   74 div.admonition, div.attention, div.caution, div.danger, div.error,
   75 div.hint, div.important, div.note, div.tip, div.warning {
   76   margin: 2em ;
   77   border: medium outset ;
   78   padding: 1em }
   79 
   80 div.admonition p.admonition-title, div.hint p.admonition-title,
   81 div.important p.admonition-title, div.note p.admonition-title,
   82 div.tip p.admonition-title {
   83   font-weight: bold ;
   84   font-family: sans-serif }
   85 
   86 div.attention p.admonition-title, div.caution p.admonition-title,
   87 div.danger p.admonition-title, div.error p.admonition-title,
   88 div.warning p.admonition-title, .code .error {
   89   color: red ;
   90   font-weight: bold ;
   91   font-family: sans-serif }
   92 
   93 /* Uncomment (and remove this text!) to get reduced vertical space in
   94    compound paragraphs.
   95 div.compound .compound-first, div.compound .compound-middle {
   96   margin-bottom: 0.5em }
   97 
   98 div.compound .compound-last, div.compound .compound-middle {
   99   margin-top: 0.5em }
  100 */
  101 
  102 div.dedication {
  103   margin: 2em 5em ;
  104   text-align: center ;
  105   font-style: italic }
  106 
  107 div.dedication p.topic-title {
  108   font-weight: bold ;
  109   font-style: normal }
  110 
  111 div.figure {
  112   margin-left: 2em ;
  113   margin-right: 2em }
  114 
  115 div.footer, div.header {
  116   clear: both;
  117   font-size: smaller }
  118 
  119 div.line-block {
  120   display: block ;
  121   margin-top: 1em ;
  122   margin-bottom: 1em }
  123 
  124 div.line-block div.line-block {
  125   margin-top: 0 ;
  126   margin-bottom: 0 ;
  127   margin-left: 1.5em }
  128 
  129 div.sidebar {
  130   margin: 0 0 0.5em 1em ;
  131   border: medium outset ;
  132   padding: 1em ;
  133   background-color: #ffffee ;
  134   width: 40% ;
  135   float: right ;
  136   clear: right }
  137 
  138 div.sidebar p.rubric {
  139   font-family: sans-serif ;
  140   font-size: medium }
  141 
  142 div.system-messages {
  143   margin: 5em }
  144 
  145 div.system-messages h1 {
  146   color: red }
  147 
  148 div.system-message {
  149   border: medium outset ;
  150   padding: 1em }
  151 
  152 div.system-message p.system-message-title {
  153   color: red ;
  154   font-weight: bold }
  155 
  156 div.topic {
  157   margin: 2em }
  158 
  159 h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
  160 h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
  161   margin-top: 0.4em }
  162 
  163 h1.title {
  164   text-align: center }
  165 
  166 h2.subtitle {
  167   text-align: center }
  168 
  169 hr.docutils {
  170   width: 75% }
  171 
  172 img.align-left, .figure.align-left, object.align-left, table.align-left {
  173   clear: left ;
  174   float: left ;
  175   margin-right: 1em }
  176 
  177 img.align-right, .figure.align-right, object.align-right, table.align-right {
  178   clear: right ;
  179   float: right ;
  180   margin-left: 1em }
  181 
  182 img.align-center, .figure.align-center, object.align-center {
  183   display: block;
  184   margin-left: auto;
  185   margin-right: auto;
  186 }
  187 
  188 table.align-center {
  189   margin-left: auto;
  190   margin-right: auto;
  191 }
  192 
  193 .align-left {
  194   text-align: left }
  195 
  196 .align-center {
  197   clear: both ;
  198   text-align: center }
  199 
  200 .align-right {
  201   text-align: right }
  202 
  203 /* reset inner alignment in figures */
  204 div.align-right {
  205   text-align: inherit }
  206 
  207 /* div.align-center * { */
  208 /*   text-align: left } */
  209 
  210 .align-top    {
  211   vertical-align: top }
  212 
  213 .align-middle {
  214   vertical-align: middle }
  215 
  216 .align-bottom {
  217   vertical-align: bottom }
  218 
  219 ol.simple, ul.simple {
  220   margin-bottom: 1em }
  221 
  222 ol.arabic {
  223   list-style: decimal }
  224 
  225 ol.loweralpha {
  226   list-style: lower-alpha }
  227 
  228 ol.upperalpha {
  229   list-style: upper-alpha }
  230 
  231 ol.lowerroman {
  232   list-style: lower-roman }
  233 
  234 ol.upperroman {
  235   list-style: upper-roman }
  236 
  237 p.attribution {
  238   text-align: right ;
  239   margin-left: 50% }
  240 
  241 p.caption {
  242   font-style: italic }
  243 
  244 p.credits {
  245   font-style: italic ;
  246   font-size: smaller }
  247 
  248 p.label {
  249   white-space: nowrap }
  250 
  251 p.rubric {
  252   font-weight: bold ;
  253   font-size: larger ;
  254   color: maroon ;
  255   text-align: center }
  256 
  257 p.sidebar-title {
  258   font-family: sans-serif ;
  259   font-weight: bold ;
  260   font-size: larger }
  261 
  262 p.sidebar-subtitle {
  263   font-family: sans-serif ;
  264   font-weight: bold }
  265 
  266 p.topic-title {
  267   font-weight: bold }
  268 
  269 pre.address {
  270   margin-bottom: 0 ;
  271   margin-top: 0 ;
  272   font: inherit }
  273 
  274 pre.literal-block, pre.doctest-block, pre.math, pre.code {
  275   margin-left: 2em ;
  276   margin-right: 2em }
  277 
  278 pre.code .ln { color: grey; } /* line numbers */
  279 pre.code, code { background-color: #eeeeee }
  280 pre.code .comment, code .comment { color: #5C6576 }
  281 pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
  282 pre.code .literal.string, code .literal.string { color: #0C5404 }
  283 pre.code .name.builtin, code .name.builtin { color: #352B84 }
  284 pre.code .deleted, code .deleted { background-color: #DEB0A1}
  285 pre.code .inserted, code .inserted { background-color: #A3D289}
  286 
  287 span.classifier {
  288   font-family: sans-serif ;
  289   font-style: oblique }
  290 
  291 span.classifier-delimiter {
  292   font-family: sans-serif ;
  293   font-weight: bold }
  294 
  295 span.interpreted {
  296   font-family: sans-serif }
  297 
  298 span.option {
  299   white-space: nowrap }
  300 
  301 span.pre {
  302   white-space: pre }
  303 
  304 span.problematic {
  305   color: red }
  306 
  307 span.section-subtitle {
  308   /* font-size relative to parent (h1..h6 element) */
  309   font-size: 80% }
  310 
  311 table.citation {
  312   border-left: solid 1px gray;
  313   margin-left: 1px }
  314 
  315 table.docinfo {
  316   margin: 2em 4em }
  317 
  318 table.docutils {
  319   margin-top: 0.5em ;
  320   margin-bottom: 0.5em }
  321 
  322 table.footnote {
  323   border-left: solid 1px black;
  324   margin-left: 1px }
  325 
  326 table.docutils td, table.docutils th,
  327 table.docinfo td, table.docinfo th {
  328   padding-left: 0.5em ;
  329   padding-right: 0.5em ;
  330   vertical-align: top }
  331 
  332 table.docutils th.field-name, table.docinfo th.docinfo-name {
  333   font-weight: bold ;
  334   text-align: left ;
  335   white-space: nowrap ;
  336   padding-left: 0 }
  337 
  338 /* "booktabs" style (no vertical lines) */
  339 table.docutils.booktabs {
  340   border: 0px;
  341   border-top: 2px solid;
  342   border-bottom: 2px solid;
  343   border-collapse: collapse;
  344 }
  345 table.docutils.booktabs * {
  346   border: 0px;
  347 }
  348 table.docutils.booktabs th {
  349   border-bottom: thin solid;
  350   text-align: left;
  351 }
  352 
  353 h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
  354 h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
  355   font-size: 100% }
  356 
  357 ul.auto-toc {
  358   list-style-type: none }
  359 
  360 </style>
  361 </head>
  362 <body>
  363 <div class="document" id="xapian-postingsource">
  364 <h1 class="title">Xapian::PostingSource</h1>
  365 
  366 <!-- Copyright (C) 2008,2009,2010,2011,2013 Olly Betts -->
  367 <!-- Copyright (C) 2008,2009 Lemur Consulting Ltd -->
  368 <div class="contents topic" id="table-of-contents">
  369 <p class="topic-title first">Table of contents</p>
  370 <ul class="simple">
  371 <li><a class="reference internal" href="#introduction" id="id1">Introduction</a></li>
  372 <li><a class="reference internal" href="#anatomy" id="id2">Anatomy</a></li>
  373 <li><a class="reference internal" href="#examples" id="id3">Examples</a></li>
  374 <li><a class="reference internal" href="#multiple-databases-and-remote-databases" id="id4">Multiple databases, and remote databases</a></li>
  375 </ul>
  376 </div>
  377 <div class="section" id="introduction">
  378 <h1><a class="toc-backref" href="#id1">Introduction</a></h1>
  379 <p>Xapian::PostingSource is an API class which you can subclass to feed data to
  380 Xapian's matcher.  This feature can be made use of in a number of ways - for
  381 example:</p>
  382 <p>As a filter - a subclass could return a stream of document ids to filter a
  383 query against.</p>
  384 <p>As a weight boost - a subclass could return every document, but with a
  385 varying weight so that certain documents receive a weight boost.  This could
  386 be used to prefer documents based on some external factor, such as age,
  387 price, proximity to a physical location, link analysis score, etc.</p>
  388 <p>As an alternative way of ranking documents - if the weighting scheme is set
  389 to Xapian::BoolWeight, then the ranking will be entirely by the weight
  390 returned by Xapian::PostingSource.</p>
  391 </div>
  392 <div class="section" id="anatomy">
  393 <h1><a class="toc-backref" href="#id2">Anatomy</a></h1>
  394 <p>When first constructed, a PostingSource is not tied to a particular database.
  395 Before Xapian can get any postings (or statistics) from the source, it needs to
  396 be supplied with a database.  This is performed by the init() method, which is
  397 passed a single parameter holding the database to use.  This method will always
  398 be called before asking for any information about the postings in the list.  If
  399 a posting source is used for multiple searches, the init() method will be
  400 called before each search; implementations must cope with init() being called
  401 multiple times, and should always use the database provided in the most recent
  402 call:</p>
  403 <pre class="literal-block">
  404 virtual void init(const Xapian::Database &amp; db) = 0;
  405 </pre>
  406 <p>Three methods return statistics independent of the iteration position.
  407 These are upper and lower bounds for the number of documents which can
  408 be returned, and an estimate of this number:</p>
  409 <pre class="literal-block">
  410 virtual Xapian::doccount get_termfreq_min() const = 0;
  411 virtual Xapian::doccount get_termfreq_max() const = 0;
  412 virtual Xapian::doccount get_termfreq_est() const = 0;
  413 </pre>
  414 <p>These methods are pure-virtual in the base class, so you have to define
  415 them when deriving your subclass.</p>
  416 <p>It must always be true that:</p>
  417 <pre class="literal-block">
  418 get_termfreq_min() &lt;= get_termfreq_est() &lt;= get_termfreq_max()
  419 </pre>
  420 <p>PostingSources must always return documents in increasing document ID order.</p>
  421 <p>After construction, a PostingSource points to a position <em>before</em> the first
  422 document id - so before a docid can be read, the position must be advanced
  423 by calling <tt class="docutils literal">next()</tt>, <tt class="docutils literal">skip_to()</tt> or <tt class="docutils literal">check()</tt>.</p>
  424 <p>The <tt class="docutils literal">get_weight()</tt> method returns the weight that you want to contribute
  425 to the current document.  This weight must always be &gt;= 0:</p>
  426 <pre class="literal-block">
  427 virtual double get_weight() const;
  428 </pre>
  429 <p>The default implementation of <tt class="docutils literal">get_weight()</tt> returns 0, for convenience when
  430 deriving &quot;weight-less&quot; subclasses.</p>
  431 <p>You also need to specify an upper bound on the value which <tt class="docutils literal">get_weight()</tt> can
  432 return, which is used by the matcher to perform various optimisations.  You
  433 should try hard to find a bound for efficiency, but if there really isn't one
  434 then you can set <tt class="docutils literal">DBL_MAX</tt>:</p>
  435 <pre class="literal-block">
  436 void get_maxweight(double max_weight);
  437 </pre>
  438 <p>This method specifies an upper bound on what <tt class="docutils literal">get_weight()</tt> will return <em>from
  439 now on</em> (until the next call to <tt class="docutils literal">init()</tt>).  So if you know that the upper
  440 bound has decreased, you should call <tt class="docutils literal">set_maxweight()</tt> with the new reduced
  441 bound.</p>
  442 <p>One thing to be aware of is that currently calling <tt class="docutils literal">set_maxweight()</tt> during
  443 the match triggers an recursion through the postlist tree to recalculate the
  444 new overall maxweight, which takes a comparable amount of time to calculating
  445 the weight for a matching document.  If your maxweight reduces for nearly
  446 every document, you may want to profile to see if it's beneficial to notify
  447 every single change.  Experiments with a modified <tt class="docutils literal">FixedWeightPostingSource</tt>
  448 which forces a pointless recalculation for every document suggest a worst case
  449 overhead in search times of about 37%, but reports of profiling results for
  450 real world examples are most welcome.  In real cases, this overhead could
  451 easily be offset by the extra scope for matcher optimisations which a tighter
  452 maxweight bound allows.</p>
  453 <p>A simple approach to reducing the number of calculations is only to do it every
  454 N documents.  If it's cheap to calculate the maxweight in your posting source,
  455 a more sophisticated strategy might be to decide an absolute maximum number of
  456 times to update the maxweight (say 100) and then to call it whenever:</p>
  457 <pre class="literal-block">
  458 last_notified_maxweight - new_maxweight &gt;= original_maxweight / 100.0
  459 </pre>
  460 <p>This ensures that only reasonably significant drops result in a recalculation
  461 of the maxweight.</p>
  462 <p>Since <tt class="docutils literal">get_weight()</tt> must always return &gt;= 0, the upper bound must clearly
  463 also always be &gt;= 0 too.  If you don't call <tt class="docutils literal">get_maxweight()</tt> then the
  464 bound defaults to 0, to match the default implementation of <tt class="docutils literal">get_weight()</tt>.</p>
  465 <p>If you want to read the currently set upper bound, you can call:</p>
  466 <pre class="literal-block">
  467 double get_maxweight() const;
  468 </pre>
  469 <p>This is just a getter method for a member variable in the
  470 <tt class="docutils literal"><span class="pre">Xapian::PostingSource</span></tt> class, and is inlined from the API headers, so
  471 there's no point storing this yourself in your subclass - it should be just as
  472 efficient to call <tt class="docutils literal">get_maxweight()</tt> whenever you want to use it.</p>
  473 <p>The <tt class="docutils literal">at_end()</tt> method checks if the current iteration position is past the
  474 last entry:</p>
  475 <pre class="literal-block">
  476 virtual bool at_end() const = 0;
  477 </pre>
  478 <p>The <tt class="docutils literal">get_docid()</tt> method returns the document id at the current iteration
  479 position:</p>
  480 <pre class="literal-block">
  481 virtual Xapian::docid get_docid() const = 0;
  482 </pre>
  483 <p>There are three methods which advance the current position.  All of these take
  484 a Xapian::Weight parameter <tt class="docutils literal">min_wt</tt>, which indicates the minimum weight
  485 contribution which the matcher is interested in.  The matcher still checks
  486 the weight of documents so it's OK to ignore this parameter completely, or to
  487 use it to discard only some documents.  But it can be useful for optimising
  488 in some cases.</p>
  489 <p>The simplest of these three methods is <tt class="docutils literal">next()</tt>, which simply advances the
  490 iteration position to the next document (possibly skipping documents with
  491 weight contribution &lt; min_wt):</p>
  492 <pre class="literal-block">
  493 virtual void next(double min_wt) = 0;
  494 </pre>
  495 <p>Then there's <tt class="docutils literal">skip_to()</tt>.  This advances the iteration position to the next
  496 document with document id &gt;= that specified (possibly also skipping documents
  497 with weight contribution &lt; min_wt):</p>
  498 <pre class="literal-block">
  499 virtual void skip_to(Xapian::docid did, double min_wt);
  500 </pre>
  501 <p>A default implementation of <tt class="docutils literal">skip_to()</tt> is provided which just calls
  502 <tt class="docutils literal">next()</tt> repeatedly.  This works but <tt class="docutils literal">skip_to()</tt> can often be implemented
  503 much more efficiently.</p>
  504 <p>The final method of this group is <tt class="docutils literal">check()</tt>.  In some cases, it's fairly
  505 cheap to check if a given document matches, but the requirement that
  506 <tt class="docutils literal">skip_to()</tt> must leave the iteration position on the next document is
  507 rather costly to implement (for example, it might require linear scanning
  508 of document ids).  To avoid this where possible, the <tt class="docutils literal">check()</tt> method
  509 allows the matcher to just check if a given document matches:</p>
  510 <pre class="literal-block">
  511 virtual bool check(Xapian::docid did, double min_wt);
  512 </pre>
  513 <p>The return value is <tt class="docutils literal">true</tt> if the method leaves the iteration position valid,
  514 and <tt class="docutils literal">false</tt> if it doesn't.  In the latter case, <tt class="docutils literal">next()</tt> will advance to
  515 the first matching position after document id <tt class="docutils literal">did</tt>, and <tt class="docutils literal">skip_to()</tt> will
  516 act as it would if the iteration position was the first matching position
  517 after <tt class="docutils literal">did</tt>.</p>
  518 <p>The default implementation of <tt class="docutils literal">check()</tt> is just a thin wrapper around
  519 <tt class="docutils literal">skip_to()</tt> which returns true - you should use this if <tt class="docutils literal">skip_to()</tt> incurs
  520 only a small extra cost.</p>
  521 <p>There's also a method to return a string describing this object:</p>
  522 <pre class="literal-block">
  523 virtual std::string get_description() const;
  524 </pre>
  525 <p>The default implementation returns a generic answer.  This default is provided
  526 to avoid forcing you to provide an implementation if you don't really care
  527 what <tt class="docutils literal">get_description()</tt> gives for your sub-class.</p>
  528 </div>
  529 <div class="section" id="examples">
  530 <h1><a class="toc-backref" href="#id3">Examples</a></h1>
  531 <p>Here is an example of a Python PostingSource which contributes additional
  532 weight from some external source (note that in Python, you call <tt class="docutils literal">next()</tt>
  533 on an iterator to get each item, including the first, which is exactly
  534 the semantics we need to implement here):</p>
  535 <pre class="literal-block">
  536 class ExternalWeightPostingSource(xapian.PostingSource):
  537     &quot;&quot;&quot;
  538     A Xapian posting source returning weights from an external source.
  539     &quot;&quot;&quot;
  540     def __init__(self, db, wtsource):
  541         xapian.PostingSource.__init__(self)
  542         self.db = db
  543         self.wtsource = wtsource
  544 
  545     def init(self, db):
  546         self.alldocs = db.postlist('')
  547 
  548     def get_termfreq_min(self): return 0
  549     def get_termfreq_est(self): return self.db.get_doccount()
  550     def get_termfreq_max(self): return self.db.get_doccount()
  551 
  552     def next(self, minweight):
  553         try:
  554             self.current = self.alldocs.next()
  555         except StopIteration:
  556             self.current = None
  557 
  558     def skip_to(self, docid, minweight):
  559         try:
  560             self.current = self.alldocs.skip_to(docid)
  561         except StopIteration:
  562             self.current = None
  563 
  564     def at_end(self):
  565         return self.current is None
  566 
  567     def get_docid(self):
  568         return self.current.docid
  569 
  570     def get_maxweight(self):
  571         return self.wtsource.get_maxweight()
  572 
  573     def get_weight(self):
  574         doc = self.db.get_document(self.current.docid)
  575         return self.wtsource.get_weight(doc)
  576 </pre>
  577 <p>ExternalWeightPostingSource doesn't restrict which documents match - it's
  578 intended to be combined with an existing query using <cite>OP_AND_MAYBE</cite> like so:</p>
  579 <pre class="literal-block">
  580 extwtps = xapian.ExternalWeightPostingSource(db, wtsource)
  581 query = xapian.Query(query.OP_AND_MAYBE, query, xapian.Query(extwtps))
  582 </pre>
  583 <p>The wtsource would be a class like this one:</p>
  584 <pre class="literal-block">
  585 class WeightSource(object):
  586     def get_maxweight(self):
  587         return 12.34;
  588 
  589     def get_weight(self, doc):
  590         return some_func(doc.get_docid())
  591 </pre>
  592 <!-- FIXME: Provide some more examples! -->
  593 <!-- FIXME "why you might want to do this" (e.g. scenario) too -->
  594 </div>
  595 <div class="section" id="multiple-databases-and-remote-databases">
  596 <h1><a class="toc-backref" href="#id4">Multiple databases, and remote databases</a></h1>
  597 <p>In order to work with searches across multiple databases, or in remote
  598 databases, some additional methods need to be implemented in your
  599 Xapian::PostingSource subclass.  The first of these is <tt class="docutils literal">clone()</tt>, which is
  600 used for multi database searches.  This method should just return a newly
  601 allocated instance of the same posting source class, initialised in the same
  602 way as the source that clone() was called on.  The returned source will be
  603 deallocated by the caller (using &quot;delete&quot; - so you should allocate it with
  604 &quot;new&quot;).</p>
  605 <p>If you don't care about supporting searches across multiple databases, you can
  606 simply return NULL from this method.  In fact, the default implementation does
  607 this, so you can just leave the default implementation in place.  If
  608 <tt class="docutils literal">clone()</tt> returns NULL, an attempt to perform a search with multiple
  609 databases will raise an exception:</p>
  610 <pre class="literal-block">
  611 virtual PostingSource * clone() const;
  612 </pre>
  613 <p>To work with searches across remote databases, you need to implement a few more
  614 methods.  Firstly, you need to implement the <tt class="docutils literal">name()</tt> method.  This simply
  615 returns the name of your posting source (fully qualified with any namespace):</p>
  616 <pre class="literal-block">
  617 virtual std::string name() const;
  618 </pre>
  619 <p>Next, you need to implement the serialise and unserialise methods.  The
  620 <tt class="docutils literal">serialise()</tt> method converts all the settings of the PostingSource to a
  621 string, and the <tt class="docutils literal">unserialise()</tt> method converts one of these strings back
  622 into a PostingSource.  Note that the serialised string doesn't need to include
  623 any information about the current iteration position of the PostingSource:</p>
  624 <pre class="literal-block">
  625 virtual std::string serialise() const;
  626 virtual PostingSource * unserialise(const std::string &amp;s) const;
  627 </pre>
  628 <p>Finally, you need to make a remote server which knows about your PostingSource.
  629 Currently, the only way to do this is to modify the source slightly, and
  630 compile your own xapian-tcpsrv.  To do this, you need to edit
  631 <tt class="docutils literal"><span class="pre">xapian-core/bin/xapian-tcpsrv.cc</span></tt> and find the
  632 <tt class="docutils literal">register_user_weighting_schemes()</tt> function.  If <tt class="docutils literal">MyPostingSource</tt> is your
  633 posting source, at the end of this function, add these lines:</p>
  634 <pre class="literal-block">
  635 Xapian::Registry registry;
  636 registry.register_postingsource(MyPostingSource());
  637 server.set_registry(registry);
  638 </pre>
  639 </div>
  640 </div>
  641 </body>
  642 </html>