You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucy.apache.org by mi...@apache.org on 2010/10/14 10:48:40 UTC

[lucy-commits] svn commit: r1022422 [20/43] - in /incubator/lucy/trunk/import: ./ charmonizer/ charmonizer/src/ charmonizer/src/Charmonizer/ charmonizer/src/Charmonizer/Core/ charmonizer/src/Charmonizer/Probe/ charmonizer/src/Charmonizer/Test/ clownfish/ clownfish/li...

Added: incubator/lucy/trunk/import/core/KinoSearch/Search/NOTQuery.cfh
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/import/core/KinoSearch/Search/NOTQuery.cfh?rev=1022422&view=auto
==============================================================================
--- incubator/lucy/trunk/import/core/KinoSearch/Search/NOTQuery.cfh (added)
+++ incubator/lucy/trunk/import/core/KinoSearch/Search/NOTQuery.cfh Thu Oct 14 08:48:04 2010
@@ -0,0 +1,71 @@
+parcel KinoSearch cnick Kino;
+
+/** Invert the result set of another Query.
+ * 
+ * A NOTQuery wraps another Query and matches against its inverse document
+ * set.  All matching docs recieve a score of 0.0.
+ *
+ * NOTQuery is often used in conjunction with ANDQuery to provide 
+ * "a AND NOT b" semantics.
+ */
+
+class KinoSearch::Search::NOTQuery inherits KinoSearch::Search::PolyQuery 
+    : dumpable {
+
+    /**
+     * @param negated_query The Query to be inverted.
+     */
+    inert incremented NOTQuery*
+    new(Query *negated_query);
+
+    /**
+     * @param negated_query The Query whose result set should be inverted.
+     */
+    public inert NOTQuery*
+    init(NOTQuery *self, Query *negated_query);
+
+    /** Accessor for the object's negated query. */
+    public Query*
+    Get_Negated_Query(NOTQuery *self);
+
+    /** Setter for the object's negated query. */
+    public void
+    Set_Negated_Query(NOTQuery *self, Query *negated_query);
+
+    public incremented Compiler*
+    Make_Compiler(NOTQuery *self, Searcher *searcher, float boost);
+
+    public incremented CharBuf*
+    To_String(NOTQuery *self);
+
+    public bool_t
+    Equals(NOTQuery *self, Obj *other);
+}
+
+class KinoSearch::Search::NOTCompiler 
+    inherits KinoSearch::Search::PolyCompiler {
+
+    inert incremented NOTCompiler*
+    new(NOTQuery *parent, Searcher *searcher, float boost);
+
+    inert NOTCompiler*
+    init(NOTCompiler *self, NOTQuery *parent, Searcher *searcher, 
+         float boost);
+
+    public incremented nullable Matcher*
+    Make_Matcher(NOTCompiler *self, SegReader *reader, bool_t need_score);
+
+    public float
+    Sum_Of_Squared_Weights(NOTCompiler *self);
+
+    public incremented VArray*
+    Highlight_Spans(NOTCompiler *self, Searcher *searcher, 
+                    DocVector *doc_vec, const CharBuf *field);
+}
+
+/* Copyright 2006-2010 Marvin Humphrey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * under the same terms as Perl itself.
+ */
+

Added: incubator/lucy/trunk/import/core/KinoSearch/Search/NOTScorer.c
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/import/core/KinoSearch/Search/NOTScorer.c?rev=1022422&view=auto
==============================================================================
--- incubator/lucy/trunk/import/core/KinoSearch/Search/NOTScorer.c (added)
+++ incubator/lucy/trunk/import/core/KinoSearch/Search/NOTScorer.c Thu Oct 14 08:48:04 2010
@@ -0,0 +1,95 @@
+#define C_KINO_NOTSCORER
+#include "KinoSearch/Util/ToolSet.h"
+
+#include "KinoSearch/Search/NOTScorer.h"
+#include "KinoSearch/Index/Similarity.h"
+#include "KinoSearch/Plan/Schema.h"
+
+NOTScorer*
+NOTScorer_new(Matcher *negated_matcher, int32_t doc_max) 
+{
+    NOTScorer *self = (NOTScorer*)VTable_Make_Obj(NOTSCORER);
+    return NOTScorer_init(self, negated_matcher, doc_max);
+}
+
+NOTScorer*
+NOTScorer_init(NOTScorer *self, Matcher *negated_matcher, int32_t doc_max)
+{
+    VArray *children = VA_new(1);
+    VA_Push(children, INCREF(negated_matcher));
+    PolyMatcher_init((PolyMatcher*)self, children, NULL);
+
+    // Init. 
+    self->doc_id           = 0;
+    self->next_negation    = 0;
+
+    // Assign. 
+    self->negated_matcher   = (Matcher*)INCREF(negated_matcher);
+    self->doc_max          = doc_max;
+
+    DECREF(children);
+
+    return self;
+}
+
+void
+NOTScorer_destroy(NOTScorer *self) 
+{
+    DECREF(self->negated_matcher);
+    SUPER_DESTROY(self, NOTSCORER);
+}
+
+int32_t
+NOTScorer_next(NOTScorer *self)
+{
+    while (1) {
+        self->doc_id++;
+
+        // Get next negated doc id. 
+        if (self->next_negation < self->doc_id) {
+            self->next_negation 
+                = Matcher_Advance(self->negated_matcher, self->doc_id);
+            if (self->next_negation == 0) {
+                DECREF(self->negated_matcher);
+                self->negated_matcher = NULL;
+                self->next_negation = self->doc_max + 1;
+            }
+        }
+
+        if (self->doc_id > self->doc_max) {
+            self->doc_id = self->doc_max; // halt advance 
+            return 0;
+        }
+        else if (self->doc_id != self->next_negation) {
+            // Success! 
+            return self->doc_id;
+        }
+    }
+}
+
+int32_t
+NOTScorer_advance(NOTScorer *self, int32_t target)
+{
+    self->doc_id = target - 1;
+    return NOTScorer_next(self);
+}
+
+int32_t
+NOTScorer_get_doc_id(NOTScorer *self)
+{
+    return self->doc_id;
+}
+
+float
+NOTScorer_score(NOTScorer *self)
+{
+    UNUSED_VAR(self);
+    return 0.0f;
+}
+
+/* Copyright 2007-2010 Marvin Humphrey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * under the same terms as Perl itself.
+ */
+

Propchange: incubator/lucy/trunk/import/core/KinoSearch/Search/NOTScorer.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/lucy/trunk/import/core/KinoSearch/Search/NOTScorer.cfh
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/import/core/KinoSearch/Search/NOTScorer.cfh?rev=1022422&view=auto
==============================================================================
--- incubator/lucy/trunk/import/core/KinoSearch/Search/NOTScorer.cfh (added)
+++ incubator/lucy/trunk/import/core/KinoSearch/Search/NOTScorer.cfh Thu Oct 14 08:48:04 2010
@@ -0,0 +1,40 @@
+parcel KinoSearch cnick Kino;
+
+/** Return the inverse of a Matcher's set.  Scores are always 0.
+ */
+
+class KinoSearch::Search::NOTScorer inherits KinoSearch::Search::PolyMatcher {
+
+    Matcher       *negated_matcher; 
+    int32_t        doc_id;
+    int32_t        doc_max;
+    int32_t        next_negation;
+
+    inert incremented NOTScorer* 
+    new(Matcher* negated_matcher, int32_t doc_max);
+
+    inert NOTScorer* 
+    init(NOTScorer *self, Matcher *negated_matcher, int32_t doc_max);
+
+    public void
+    Destroy(NOTScorer *self);
+
+    public int32_t
+    Next(NOTScorer *self);
+
+    public int32_t
+    Advance(NOTScorer *self, int32_t target);
+
+    public float
+    Score(NOTScorer *self);
+
+    public int32_t 
+    Get_Doc_ID(NOTScorer *self);
+}
+
+/* Copyright 2006-2010 Marvin Humphrey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * under the same terms as Perl itself.
+ */
+

Added: incubator/lucy/trunk/import/core/KinoSearch/Search/NoMatchQuery.c
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/import/core/KinoSearch/Search/NoMatchQuery.c?rev=1022422&view=auto
==============================================================================
--- incubator/lucy/trunk/import/core/KinoSearch/Search/NoMatchQuery.c (added)
+++ incubator/lucy/trunk/import/core/KinoSearch/Search/NoMatchQuery.c Thu Oct 14 08:48:04 2010
@@ -0,0 +1,91 @@
+#define C_KINO_NOMATCHQUERY
+#include "KinoSearch/Util/ToolSet.h"
+
+#include "KinoSearch/Search/NoMatchQuery.h"
+#include "KinoSearch/Index/SegReader.h"
+#include "KinoSearch/Index/Similarity.h"
+#include "KinoSearch/Plan/Schema.h"
+#include "KinoSearch/Search/NoMatchScorer.h"
+#include "KinoSearch/Search/Searcher.h"
+#include "KinoSearch/Store/InStream.h"
+#include "KinoSearch/Store/OutStream.h"
+#include "KinoSearch/Util/Freezer.h"
+
+NoMatchQuery*
+NoMatchQuery_new()
+{
+    NoMatchQuery *self = (NoMatchQuery*)VTable_Make_Obj(NOMATCHQUERY);
+    return NoMatchQuery_init(self);
+}
+
+NoMatchQuery*
+NoMatchQuery_init(NoMatchQuery *self)
+{
+    return (NoMatchQuery*)Query_init((Query*)self, 0.0f);
+}
+
+bool_t
+NoMatchQuery_equals(NoMatchQuery *self, Obj *other)
+{
+    NoMatchQuery *evil_twin = (NoMatchQuery*)other;
+    if (!Obj_Is_A(other, NOMATCHQUERY)) return false;
+    if (self->boost != evil_twin->boost) return false;
+    return true;
+}
+
+CharBuf*
+NoMatchQuery_to_string(NoMatchQuery *self)
+{
+    UNUSED_VAR(self);
+    return CB_new_from_trusted_utf8("[NOMATCH]", 9);
+}
+
+Compiler*
+NoMatchQuery_make_compiler(NoMatchQuery *self, Searcher *searcher, 
+                            float boost)
+{
+    return (Compiler*)NoMatchCompiler_new(self, searcher, boost);
+}
+
+/**********************************************************************/
+
+NoMatchCompiler*
+NoMatchCompiler_new(NoMatchQuery *parent, Searcher *searcher, 
+                     float boost)
+{
+    NoMatchCompiler *self 
+        = (NoMatchCompiler*)VTable_Make_Obj(NOMATCHCOMPILER);
+    return NoMatchCompiler_init(self, parent, searcher, boost);
+}
+
+NoMatchCompiler*
+NoMatchCompiler_init(NoMatchCompiler *self, NoMatchQuery *parent, 
+                      Searcher *searcher, float boost)
+{
+    return (NoMatchCompiler*)Compiler_init((Compiler*)self, 
+        (Query*)parent, searcher, NULL, boost);
+}
+
+NoMatchCompiler*
+NoMatchCompiler_deserialize(NoMatchCompiler *self, InStream *instream)
+{
+    self = self ? self : (NoMatchCompiler*)VTable_Make_Obj(NOMATCHCOMPILER);
+    return (NoMatchCompiler*)Compiler_deserialize((Compiler*)self, instream);
+}
+
+Matcher*
+NoMatchCompiler_make_matcher(NoMatchCompiler *self, SegReader *reader, 
+                             bool_t need_score)
+{
+    UNUSED_VAR(self);
+    UNUSED_VAR(reader);
+    UNUSED_VAR(need_score);
+    return (Matcher*)NoMatchScorer_new();
+}
+
+/* Copyright 2008-2010 Marvin Humphrey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * under the same terms as Perl itself.
+ */
+

Propchange: incubator/lucy/trunk/import/core/KinoSearch/Search/NoMatchQuery.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/lucy/trunk/import/core/KinoSearch/Search/NoMatchQuery.cfh
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/import/core/KinoSearch/Search/NoMatchQuery.cfh?rev=1022422&view=auto
==============================================================================
--- incubator/lucy/trunk/import/core/KinoSearch/Search/NoMatchQuery.cfh (added)
+++ incubator/lucy/trunk/import/core/KinoSearch/Search/NoMatchQuery.cfh Thu Oct 14 08:48:04 2010
@@ -0,0 +1,52 @@
+parcel KinoSearch cnick Kino;
+
+/** Query which matches no documents.
+ *
+ * NoMatchQuery is a utility class representing a query which matches nothing.
+ * Typical usage might include e.g. returning a NoMatchQuery when a
+ * QueryParser is asked to parse an empty string.
+ */
+class KinoSearch::Search::NoMatchQuery inherits KinoSearch::Search::Query
+    : dumpable {
+
+    inert incremented NoMatchQuery*
+    new();
+
+    /** Constructor. Takes no arguments.
+     */
+    public inert NoMatchQuery*
+    init(NoMatchQuery *self);
+
+    public bool_t
+    Equals(NoMatchQuery *self, Obj *other);
+
+    public incremented CharBuf*
+    To_String(NoMatchQuery *self);
+
+    public incremented Compiler*
+    Make_Compiler(NoMatchQuery *self, Searcher *searcher, float boost);
+}
+
+class KinoSearch::Search::NoMatchCompiler 
+    inherits KinoSearch::Search::Compiler {
+
+    inert incremented NoMatchCompiler*
+    new(NoMatchQuery *parent, Searcher *searcher, float boost);
+
+    inert NoMatchCompiler*
+    init(NoMatchCompiler *self, NoMatchQuery *parent,
+         Searcher *searcher, float boost);
+
+    public incremented nullable Matcher*
+    Make_Matcher(NoMatchCompiler *self, SegReader *reader, bool_t need_score);
+    
+    public incremented NoMatchCompiler*
+    Deserialize(NoMatchCompiler *self, InStream *instream);
+}
+
+/* Copyright 2008-2010 Marvin Humphrey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * under the same terms as Perl itself.
+ */
+

Added: incubator/lucy/trunk/import/core/KinoSearch/Search/NoMatchScorer.c
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/import/core/KinoSearch/Search/NoMatchScorer.c?rev=1022422&view=auto
==============================================================================
--- incubator/lucy/trunk/import/core/KinoSearch/Search/NoMatchScorer.c (added)
+++ incubator/lucy/trunk/import/core/KinoSearch/Search/NoMatchScorer.c Thu Oct 14 08:48:04 2010
@@ -0,0 +1,42 @@
+#define C_KINO_NOMATCHSCORER
+#include "KinoSearch/Util/ToolSet.h"
+
+#include "KinoSearch/Search/NoMatchScorer.h"
+#include "KinoSearch/Index/IndexReader.h"
+#include "KinoSearch/Index/Similarity.h"
+#include "KinoSearch/Plan/Schema.h"
+
+NoMatchScorer*
+NoMatchScorer_new()
+{
+    NoMatchScorer *self = (NoMatchScorer*)VTable_Make_Obj(NOMATCHSCORER);
+    return NoMatchScorer_init(self);
+}
+
+NoMatchScorer*
+NoMatchScorer_init(NoMatchScorer *self)
+{
+    return (NoMatchScorer*)Matcher_init((Matcher*)self);
+}   
+
+int32_t
+NoMatchScorer_next(NoMatchScorer* self) 
+{
+    UNUSED_VAR(self);
+    return 0;
+}
+
+int32_t
+NoMatchScorer_advance(NoMatchScorer* self, int32_t target) 
+{
+    UNUSED_VAR(self);
+    UNUSED_VAR(target);
+    return 0;
+}
+
+/* Copyright 2007-2010 Marvin Humphrey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * under the same terms as Perl itself.
+ */
+

Propchange: incubator/lucy/trunk/import/core/KinoSearch/Search/NoMatchScorer.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/lucy/trunk/import/core/KinoSearch/Search/NoMatchScorer.cfh
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/import/core/KinoSearch/Search/NoMatchScorer.cfh?rev=1022422&view=auto
==============================================================================
--- incubator/lucy/trunk/import/core/KinoSearch/Search/NoMatchScorer.cfh (added)
+++ incubator/lucy/trunk/import/core/KinoSearch/Search/NoMatchScorer.cfh Thu Oct 14 08:48:04 2010
@@ -0,0 +1,23 @@
+parcel KinoSearch cnick Kino;
+
+class KinoSearch::Search::NoMatchScorer inherits KinoSearch::Search::Matcher {
+
+    inert incremented NoMatchScorer*
+    new();
+
+    inert NoMatchScorer*
+    init(NoMatchScorer *self);
+
+    public int32_t
+    Next(NoMatchScorer* self);
+
+    public int32_t
+    Advance(NoMatchScorer* self, int32_t target);
+}
+
+/* Copyright 2008-2010 Marvin Humphrey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * under the same terms as Perl itself.
+ */
+

Added: incubator/lucy/trunk/import/core/KinoSearch/Search/ORMatcher.c
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/import/core/KinoSearch/Search/ORMatcher.c?rev=1022422&view=auto
==============================================================================
--- incubator/lucy/trunk/import/core/KinoSearch/Search/ORMatcher.c (added)
+++ incubator/lucy/trunk/import/core/KinoSearch/Search/ORMatcher.c Thu Oct 14 08:48:04 2010
@@ -0,0 +1,406 @@
+#define C_KINO_ORMATCHER
+#define C_KINO_ORSCORER
+#include "KinoSearch/Util/ToolSet.h"
+
+#include "KinoSearch/Search/ORMatcher.h"
+#include "KinoSearch/Index/Similarity.h"
+
+// Add an element to the queue.  Unsafe -- bounds checking of queue size is
+// left to the caller.
+static void 
+S_add_element(ORMatcher *self, Matcher *matcher, int32_t doc_id);
+
+// Empty out the queue. 
+static void 
+S_clear(ORMatcher *self);
+
+// Call Matcher_Next() on the top queue element and adjust the queue,
+// removing the element if Matcher_Next() returns false. 
+static INLINE int32_t
+SI_top_next(ORMatcher *self);
+
+// Call Matcher_Advance() on the top queue element and adjust the queue,
+// removing the element if Matcher_Advance() returns false. 
+static INLINE int32_t
+SI_top_advance(ORMatcher *self, int32_t target);
+
+/* React to a change in the top element, or "root" -- presumably the update of
+ * its doc_id resulting from a call to Matcher_Next() or Matcher_Advance().
+ * If the Matcher has been exhausted, remove it from the queue and replace it
+ * with the bottom node (i.e. perform "root replacement").  In either case,
+ * perform a "sift down" to restore the heap property.  Return the doc id of
+ * the root node, or 0 if the queue has been emptied.
+ */
+static int32_t
+S_adjust_root(ORMatcher *self);
+
+// Take the bottom node (which probably violates the heap property when this
+// is called) and bubble it up through the heap until the heap property is
+// restored.
+static void
+S_bubble_up(ORMatcher *self);
+
+// Take the top node (which probably violates the heap property when this
+// is called) and sift it down through the heap until the heap property is
+// restored.
+static void
+S_sift_down(ORMatcher *self);
+
+ORMatcher*
+ORMatcher_new(VArray *children) 
+{
+    ORMatcher *self = (ORMatcher*)VTable_Make_Obj(ORMATCHER);
+    return ORMatcher_init(self, children);
+}
+
+static ORMatcher*
+S_ormatcher_init2(ORMatcher *self, VArray *children, Similarity *sim)
+{
+    size_t amount_to_malloc;
+    uint32_t i;
+
+    // Init. 
+    PolyMatcher_init((PolyMatcher*)self, children, sim);
+    self->size = 0;
+
+    // Derive. 
+    self->max_size = VA_Get_Size(children);
+
+    // Allocate. 
+    self->heap = (HeapedMatcherDoc**)CALLOCATE(self->max_size + 1, sizeof(HeapedMatcherDoc*));
+
+    // Create a pool of HMDs.  Encourage CPU cache hits by using a single
+    // allocation for all of them.
+    amount_to_malloc = (self->max_size + 1) * sizeof(HeapedMatcherDoc);
+    self->blob = (char*)MALLOCATE(amount_to_malloc);
+    self->pool = (HeapedMatcherDoc**)CALLOCATE(self->max_size + 1, sizeof(HeapedMatcherDoc*));
+    for (i = 1; i <= self->max_size; i++) {
+        size_t offset = i * sizeof(HeapedMatcherDoc);
+        HeapedMatcherDoc *hmd = (HeapedMatcherDoc*)(self->blob + offset);
+        self->pool[i] = hmd;
+    }
+
+    // Prime queue. 
+    for (i = 0; i < self->max_size; i++) {
+        Matcher *matcher = (Matcher*)VA_Fetch(children, i);
+        S_add_element(self, (Matcher*)INCREF(matcher), 0);
+    }
+    
+    return self;
+}
+
+ORMatcher*
+ORMatcher_init(ORMatcher *self, VArray *children)
+{
+    return S_ormatcher_init2(self, children, NULL);
+}
+
+void
+ORMatcher_destroy(ORMatcher *self)
+{
+    if (self->blob) { S_clear(self); }
+    FREEMEM(self->blob);
+    FREEMEM(self->pool);
+    FREEMEM(self->heap);
+    SUPER_DESTROY(self, ORMATCHER);
+}
+
+int32_t
+ORMatcher_next(ORMatcher *self)
+{
+    if (self->size == 0) { 
+        return 0; 
+    }
+    else {
+        int32_t last_doc_id = self->top_hmd->doc;
+        while (self->top_hmd->doc == last_doc_id) {
+            int32_t top_doc_id = SI_top_next(self);
+            if (!top_doc_id && self->size == 0) {
+                return 0;
+            }
+        }
+        return self->top_hmd->doc;
+    }
+}
+
+int32_t
+ORMatcher_advance(ORMatcher *self, int32_t target)
+{
+    if (!self->size) { return 0; }
+    do {
+        int32_t least = SI_top_advance(self, target);
+        if (least >= target) { return least; }
+        if (!least) { 
+            if (!self->size) { return 0; } 
+        }
+    } while (true);
+}
+
+int32_t
+ORMatcher_get_doc_id(ORMatcher *self)
+{
+    return self->top_hmd->doc;
+}
+
+static void 
+S_clear(ORMatcher *self) 
+{
+    HeapedMatcherDoc **const heap = self->heap;
+    HeapedMatcherDoc **const pool = self->pool;
+
+    // Node 0 is held empty, to make the algo clearer. 
+    for ( ; self->size > 0; self->size--) {
+        HeapedMatcherDoc *hmd = heap[ self->size ];
+        heap[ self->size ] = NULL;
+        DECREF(hmd->matcher);
+
+        // Put HMD back in pool. 
+        pool[ self->size ] = hmd;
+    }   
+}
+
+static INLINE int32_t
+SI_top_next(ORMatcher *self)
+{
+    HeapedMatcherDoc *const top_hmd = self->top_hmd;
+    top_hmd->doc = Matcher_Next(top_hmd->matcher);
+    return S_adjust_root(self);
+}
+
+static INLINE int32_t
+SI_top_advance(ORMatcher *self, int32_t target)
+{
+    HeapedMatcherDoc *const top_hmd = self->top_hmd;
+    top_hmd->doc = Matcher_Advance(top_hmd->matcher, target);
+    return S_adjust_root(self);
+}
+
+static void 
+S_add_element(ORMatcher *self, Matcher *matcher, int32_t doc_id)
+{
+    HeapedMatcherDoc **const heap = self->heap;
+    HeapedMatcherDoc **const pool = self->pool;
+    HeapedMatcherDoc *hmd;
+
+    // Increment size. 
+    self->size++;
+
+    // Put element at the bottom of the heap. 
+    hmd          = pool[ self->size ];
+    hmd->matcher = matcher;
+    hmd->doc     = doc_id;
+    heap[ self->size ] = hmd;
+
+    // Adjust heap. 
+    S_bubble_up(self);
+}
+
+static int32_t
+S_adjust_root(ORMatcher *self)
+{
+    HeapedMatcherDoc *const top_hmd = self->top_hmd;
+
+    // Inlined pop. 
+    if (!top_hmd->doc) {
+        HeapedMatcherDoc *const last_hmd = self->heap[ self->size ];
+
+        // Last to first. 
+        DECREF(top_hmd->matcher);
+        top_hmd->matcher = last_hmd->matcher;
+        top_hmd->doc     = last_hmd->doc;
+        self->heap[ self->size ] = NULL;
+
+        // Put back in pool. 
+        self->pool[ self->size ] = last_hmd;
+
+        self->size--;
+        if (self->size == 0) 
+            return 0;
+    }
+
+    // Move queue no matter what. 
+    S_sift_down(self);
+
+    return self->top_hmd->doc;
+}
+
+static void
+S_bubble_up(ORMatcher *self) 
+{
+    HeapedMatcherDoc **const heap = self->heap;
+    uint32_t i = self->size;
+    uint32_t j = i >> 1;
+    HeapedMatcherDoc *const node = heap[i]; // save bottom node 
+
+    while (j > 0 && node->doc < heap[j]->doc) {
+        heap[i] = heap[j];
+        i = j;
+        j = j >> 1;
+    }
+    heap[i] = node;
+    self->top_hmd = heap[1];
+}
+
+static void
+S_sift_down(ORMatcher *self) 
+{
+    HeapedMatcherDoc **const heap = self->heap;
+    uint32_t i = 1;
+    uint32_t j = i << 1;
+    uint32_t k = j + 1;
+    HeapedMatcherDoc *const node = heap[i]; // save top node 
+
+    // Find smaller child. 
+    if (k <= self->size && heap[k]->doc < heap[j]->doc) {
+        j = k;
+    }
+
+    while (j <= self->size && heap[j]->doc < node->doc) {
+        heap[i] = heap[j];
+        i = j;
+        j = i << 1;
+        k = j + 1;
+        if (k <= self->size && heap[k]->doc < heap[j]->doc) {
+            j = k;
+        }
+    }
+    heap[i] = node;
+    
+    self->top_hmd = heap[1];
+}
+
+/***************************************************************************/
+
+/* When this is called, all children are past the current self->doc_id.  The
+ * least doc_id amongst them becomes the new self->doc_id, and they are all
+ * advanced so that they are once again out in front of it.  While they are
+ * advancing, their scores are cached in an array, to be summed during
+ * Score().
+ */
+static int32_t
+S_advance_after_current(ORScorer *self);
+
+ORScorer*
+ORScorer_new(VArray *children, Similarity *sim) 
+{
+    ORScorer *self = (ORScorer*)VTable_Make_Obj(ORSCORER);
+    return ORScorer_init(self, children, sim);
+}
+
+ORScorer*
+ORScorer_init(ORScorer *self, VArray *children, Similarity *sim) 
+{
+    S_ormatcher_init2((ORMatcher*)self, children, sim);
+    self->doc_id           = 0;
+    self->scores           = (float*)MALLOCATE(self->num_kids * sizeof(float));
+
+    // Establish the state of all child matchers being past the current doc
+    // id, by invoking ORMatcher's Next() method. 
+    ORMatcher_next((ORMatcher*)self);
+
+    return self;
+}
+
+void
+ORScorer_destroy(ORScorer *self) 
+{
+    FREEMEM(self->scores);
+    SUPER_DESTROY(self, ORSCORER);
+}
+
+int32_t
+ORScorer_next(ORScorer *self)
+{
+    return S_advance_after_current(self);
+}
+
+static int32_t
+S_advance_after_current(ORScorer *self) 
+{
+    float *const     scores = self->scores;
+    Matcher *child;
+
+    // Get the top Matcher, or bail because there are no Matchers left. 
+    if (!self->size) { return 0; }
+    else             { child = self->top_hmd->matcher; }
+
+    // The top matcher will already be at the correct doc, so start there. 
+    self->doc_id        = self->top_hmd->doc;
+    scores[0]           = Matcher_Score(child);
+    self->matching_kids = 1;
+
+    do {
+        // Attempt to advance past current doc. 
+        int32_t top_doc_id = SI_top_next((ORMatcher*)self);
+        if (!top_doc_id) {
+            if (!self->size) {
+                break; // bail, no more to advance 
+            }
+        }
+
+        if (top_doc_id != self->doc_id) {
+            // Bail, least doc in queue is now past the one we're scoring. 
+            break;
+        }
+        else {
+            // Accumulate score. 
+            child = self->top_hmd->matcher;
+            scores[ self->matching_kids ] = Matcher_Score(child);
+            self->matching_kids++;
+        }
+    } while (true);
+
+    return self->doc_id;
+}
+
+int32_t
+ORScorer_advance(ORScorer *self, int32_t target)
+{
+    // Return sentinel once exhausted. 
+    if (!self->size) { return 0; }
+
+    // Succeed if we're already past and still on a valid doc. 
+    if (target <= self->doc_id) {
+        return self->doc_id;
+    }
+
+    do {
+        // If all matchers are caught up, accumulate score and return. 
+        if (self->top_hmd->doc >= target) {
+            return S_advance_after_current(self);
+        }
+
+        // Not caught up yet, so keep skipping matchers. 
+        if ( !SI_top_advance((ORMatcher*)self, target) ) {
+            if (!self->size) { return 0; }
+        }
+    } while (true);
+}
+
+int32_t
+ORScorer_get_doc_id(ORScorer *self)
+{
+    return self->doc_id;
+}
+
+float
+ORScorer_score(ORScorer *self)
+{
+    float *const scores = self->scores;
+    float score = 0.0f; 
+    uint32_t i;
+
+    // Accumulate score, then factor in coord bonus. 
+    for (i = 0; i < self->matching_kids; i++) {
+        score += scores[i];
+    }
+    score *= self->coord_factors[ self->matching_kids ];
+
+    return score;
+}
+
+/* Copyright 2007-2010 Marvin Humphrey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * under the same terms as Perl itself.
+ */

Propchange: incubator/lucy/trunk/import/core/KinoSearch/Search/ORMatcher.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/lucy/trunk/import/core/KinoSearch/Search/ORMatcher.cfh
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/import/core/KinoSearch/Search/ORMatcher.cfh?rev=1022422&view=auto
==============================================================================
--- incubator/lucy/trunk/import/core/KinoSearch/Search/ORMatcher.cfh (added)
+++ incubator/lucy/trunk/import/core/KinoSearch/Search/ORMatcher.cfh Thu Oct 14 08:48:04 2010
@@ -0,0 +1,92 @@
+parcel KinoSearch cnick Kino;
+
+__C__
+#include "KinoSearch/Search/Matcher.h"
+
+/* A wrapper for a Matcher which caches the result of Matcher_Get_Doc_ID().
+ */
+typedef struct kino_HeapedMatcherDoc {
+    kino_Matcher *matcher;
+    int32_t   doc;
+} kino_HeapedMatcherDoc;
+
+#ifdef KINO_USE_SHORT_NAMES
+  #define HeapedMatcherDoc              kino_HeapedMatcherDoc
+#endif
+
+__END_C__
+
+/** Matcher which unions the doc id sets of other Matchers using a priority
+ * queue.
+ */
+
+class KinoSearch::Search::ORMatcher inherits KinoSearch::Search::PolyMatcher {
+
+    HeapedMatcherDoc **heap;
+    HeapedMatcherDoc **pool;    /* Pool of HMDs to minimize mallocs */
+    char              *blob;    /* single allocation for all HMDs */
+    HeapedMatcherDoc  *top_hmd; /* cached top elem */
+    uint32_t           size;
+    uint32_t           max_size;
+
+    inert incremented ORMatcher*
+    new(VArray *children);
+
+    /** 
+     * @param children An array of Matchers.
+     */
+    inert incremented ORMatcher*
+    init(ORMatcher *self, VArray *children);
+
+    public void
+    Destroy(ORMatcher *self);
+
+    public int32_t
+    Next(ORMatcher *self);
+
+    public int32_t
+    Advance(ORMatcher *self, int32_t target);
+
+    public int32_t 
+    Get_Doc_ID(ORMatcher *self);
+}
+
+/**
+ * Union results of multiple Matchers.
+ * 
+ * ORScorer collates the output of multiple subscorers, summing their scores
+ * whenever they match the same document.
+ */
+class KinoSearch::Search::ORScorer inherits KinoSearch::Search::ORMatcher {
+
+    float            *scores;
+    int32_t           doc_id;
+
+    inert incremented ORScorer* 
+    new(VArray *children, Similarity *similarity);
+
+    inert ORScorer* 
+    init(ORScorer *self, VArray *children, Similarity *similarity);
+
+    public void
+    Destroy(ORScorer *self);
+
+    public int32_t
+    Next(ORScorer *self);
+
+    public int32_t
+    Advance(ORScorer *self, int32_t target);
+
+    public float
+    Score(ORScorer *self);
+
+    public int32_t 
+    Get_Doc_ID(ORScorer *self);
+}
+
+/* Copyright 2007-2010 Marvin Humphrey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * under the same terms as Perl itself.
+ */
+

Added: incubator/lucy/trunk/import/core/KinoSearch/Search/ORQuery.c
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/import/core/KinoSearch/Search/ORQuery.c?rev=1022422&view=auto
==============================================================================
--- incubator/lucy/trunk/import/core/KinoSearch/Search/ORQuery.c (added)
+++ incubator/lucy/trunk/import/core/KinoSearch/Search/ORQuery.c Thu Oct 14 08:48:04 2010
@@ -0,0 +1,136 @@
+#define C_KINO_ORQUERY
+#define C_KINO_ORCOMPILER
+#include "KinoSearch/Util/ToolSet.h"
+
+#include "KinoSearch/Search/ORQuery.h"
+#include "KinoSearch/Index/SegReader.h"
+#include "KinoSearch/Index/Similarity.h"
+#include "KinoSearch/Search/ORMatcher.h"
+#include "KinoSearch/Search/Searcher.h"
+#include "KinoSearch/Store/InStream.h"
+#include "KinoSearch/Store/OutStream.h"
+
+ORQuery*
+ORQuery_new(VArray *children)
+{
+    ORQuery *self = (ORQuery*)VTable_Make_Obj(ORQUERY);
+    return ORQuery_init(self, children);
+}
+
+ORQuery*
+ORQuery_init(ORQuery *self, VArray *children)
+{
+    return (ORQuery*)PolyQuery_init((PolyQuery*)self, children);
+}
+
+Compiler*
+ORQuery_make_compiler(ORQuery *self, Searcher *searcher, float boost)
+{
+    return (Compiler*)ORCompiler_new(self, searcher, boost);
+}
+
+bool_t
+ORQuery_equals(ORQuery *self, Obj *other)
+{
+    if ((ORQuery*)other == self)   { return true;  }
+    if (!Obj_Is_A(other, ORQUERY)) { return false; }
+    return PolyQuery_equals((PolyQuery*)self, other);
+}
+
+CharBuf*
+ORQuery_to_string(ORQuery *self)
+{
+    uint32_t num_kids = VA_Get_Size(self->children);
+    if (!num_kids) return CB_new_from_trusted_utf8("()", 2);
+    else {
+        CharBuf *retval = CB_new_from_trusted_utf8("(", 1);
+        uint32_t i;
+        uint32_t last_kid = num_kids - 1;
+        for (i = 0; i < num_kids; i++) {
+            CharBuf *kid_string = Obj_To_String(VA_Fetch(self->children, i));
+            CB_Cat(retval, kid_string);
+            DECREF(kid_string);
+            if (i == last_kid) {
+                CB_Cat_Trusted_Str(retval, ")", 1);
+            }
+            else {
+                CB_Cat_Trusted_Str(retval, " OR ", 4);
+            }
+        }
+        return retval;
+    }
+}
+
+/**********************************************************************/
+
+ORCompiler*
+ORCompiler_new(ORQuery *parent, Searcher *searcher, float boost)
+{
+    ORCompiler *self = (ORCompiler*)VTable_Make_Obj(ORCOMPILER);
+    return ORCompiler_init(self, parent, searcher, boost);
+}
+
+ORCompiler*
+ORCompiler_init(ORCompiler *self, ORQuery *parent, Searcher *searcher, 
+                 float boost)
+{
+    PolyCompiler_init((PolyCompiler*)self, (PolyQuery*)parent, searcher, 
+        boost);
+    ORCompiler_Normalize(self);
+    return self;
+}
+
+Matcher*
+ORCompiler_make_matcher(ORCompiler *self, SegReader *reader, 
+                        bool_t need_score)
+{
+    uint32_t num_kids = VA_Get_Size(self->children);
+
+    if (num_kids == 1) {
+        Compiler *only_child = (Compiler*)VA_Fetch(self->children, 0);
+        return Compiler_Make_Matcher(only_child, reader, need_score);
+    }
+    else {
+        VArray *submatchers = VA_new(num_kids);
+        uint32_t i;
+        uint32_t num_submatchers = 0;
+
+        // Accumulate sub-matchers. 
+        for (i = 0; i < num_kids; i++) {
+            Compiler *child = (Compiler*)VA_Fetch(self->children, i);
+            Matcher *submatcher 
+                = Compiler_Make_Matcher(child, reader, need_score);
+            if (submatcher != NULL) {
+                VA_Push(submatchers, (Obj*)submatcher);
+                num_submatchers++;
+            }
+        }
+
+        if (num_submatchers == 0) {
+            // No possible matches, so return null. 
+            DECREF(submatchers);
+            return NULL;
+        }
+        else if (num_submatchers == 1) {
+            // Only one submatcher, so no need for ORScorer wrapper. 
+            Matcher *submatcher = (Matcher*)INCREF(VA_Fetch(submatchers, 0));
+            DECREF(submatchers);
+            return submatcher;
+        }
+        else {
+            Similarity *sim    = ORCompiler_Get_Similarity(self);
+            Matcher    *retval = need_score
+                ? (Matcher*)ORScorer_new(submatchers, sim)
+                : (Matcher*)ORMatcher_new(submatchers);
+            DECREF(submatchers);
+            return retval;
+        }
+    }
+}
+
+/* Copyright 2006-2010 Marvin Humphrey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * under the same terms as Perl itself.
+ */
+

Propchange: incubator/lucy/trunk/import/core/KinoSearch/Search/ORQuery.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/lucy/trunk/import/core/KinoSearch/Search/ORQuery.cfh
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/import/core/KinoSearch/Search/ORQuery.cfh?rev=1022422&view=auto
==============================================================================
--- incubator/lucy/trunk/import/core/KinoSearch/Search/ORQuery.cfh (added)
+++ incubator/lucy/trunk/import/core/KinoSearch/Search/ORQuery.cfh Thu Oct 14 08:48:04 2010
@@ -0,0 +1,51 @@
+parcel KinoSearch cnick Kino;
+
+/** Union multiple result sets.
+ *
+ * ORQuery matches when any of its children match, so its result set is
+ * the union of their result sets.  Matching documents recieve a summed
+ * score from all matching child Queries.
+ */
+
+class KinoSearch::Search::ORQuery inherits KinoSearch::Search::PolyQuery 
+    : dumpable {
+
+    inert incremented ORQuery*
+    new(VArray *children = NULL);
+
+    /**
+     * @param children An array of child Queries.
+     */
+    public inert ORQuery*
+    init(ORQuery *self, VArray *children = NULL);
+
+    public incremented Compiler*
+    Make_Compiler(ORQuery *self, Searcher *searcher, float boost);
+
+    public incremented CharBuf*
+    To_String(ORQuery *self);
+
+    public bool_t
+    Equals(ORQuery *self, Obj *other);
+}
+
+class KinoSearch::Search::ORCompiler 
+    inherits KinoSearch::Search::PolyCompiler {
+
+    inert incremented ORCompiler*
+    new(ORQuery *parent, Searcher *searcher, float boost);
+
+    inert ORCompiler*
+    init(ORCompiler *self, ORQuery *parent, Searcher *searcher, 
+         float boost);
+
+    public incremented nullable Matcher*
+    Make_Matcher(ORCompiler *self, SegReader *reader, bool_t need_score);
+}
+
+/* Copyright 2006-2010 Marvin Humphrey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * under the same terms as Perl itself.
+ */
+

Added: incubator/lucy/trunk/import/core/KinoSearch/Search/PhraseQuery.c
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/import/core/KinoSearch/Search/PhraseQuery.c?rev=1022422&view=auto
==============================================================================
--- incubator/lucy/trunk/import/core/KinoSearch/Search/PhraseQuery.c (added)
+++ incubator/lucy/trunk/import/core/KinoSearch/Search/PhraseQuery.c Thu Oct 14 08:48:04 2010
@@ -0,0 +1,402 @@
+#define C_KINO_PHRASEQUERY
+#define C_KINO_PHRASECOMPILER
+#include <stdarg.h>
+
+#include "KinoSearch/Util/ToolSet.h"
+
+#include "KinoSearch/Search/PhraseQuery.h"
+#include "KinoSearch/Index/DocVector.h"
+#include "KinoSearch/Index/Posting.h"
+#include "KinoSearch/Index/Posting/ScorePosting.h"
+#include "KinoSearch/Index/PostingList.h"
+#include "KinoSearch/Index/PostingListReader.h"
+#include "KinoSearch/Index/SegPostingList.h"
+#include "KinoSearch/Index/SegReader.h"
+#include "KinoSearch/Index/Similarity.h"
+#include "KinoSearch/Index/TermVector.h"
+#include "KinoSearch/Plan/Schema.h"
+#include "KinoSearch/Search/PhraseScorer.h"
+#include "KinoSearch/Search/Searcher.h"
+#include "KinoSearch/Search/Span.h"
+#include "KinoSearch/Search/TermQuery.h"
+#include "KinoSearch/Store/InStream.h"
+#include "KinoSearch/Store/OutStream.h"
+#include "KinoSearch/Util/Freezer.h"
+
+// Shared initialization routine which assumes that it's ok to assume control
+// over [field] and [terms], eating their refcounts.
+static PhraseQuery*
+S_do_init(PhraseQuery *self, CharBuf *field, VArray *terms, float boost);
+
+PhraseQuery*
+PhraseQuery_new(const CharBuf *field, VArray *terms)
+{
+    PhraseQuery *self = (PhraseQuery*)VTable_Make_Obj(PHRASEQUERY);
+    return PhraseQuery_init(self, field, terms);
+}
+
+PhraseQuery*
+PhraseQuery_init(PhraseQuery *self, const CharBuf *field, VArray *terms)
+{
+    return S_do_init(self, CB_Clone(field), VA_Clone(terms), 1.0f);
+}
+
+void
+PhraseQuery_destroy(PhraseQuery *self)
+{
+    DECREF(self->terms);
+    DECREF(self->field);
+    SUPER_DESTROY(self, PHRASEQUERY);
+}
+
+static PhraseQuery*
+S_do_init(PhraseQuery *self, CharBuf *field, VArray *terms, float boost)
+{
+    uint32_t i, max;
+    Query_init((Query*)self, boost);
+    for (i = 0, max = VA_Get_Size(terms); i < max; i++) {
+        CERTIFY(VA_Fetch(terms, i), OBJ);
+    }
+    self->field = field;
+    self->terms = terms;
+    return self;
+}
+
+void
+PhraseQuery_serialize(PhraseQuery *self, OutStream *outstream)
+{
+    OutStream_Write_F32(outstream, self->boost);
+    CB_Serialize(self->field, outstream);
+    VA_Serialize(self->terms, outstream);
+}
+
+PhraseQuery*
+PhraseQuery_deserialize(PhraseQuery *self, InStream *instream)
+{
+    float    boost  = InStream_Read_F32(instream);
+    CharBuf *field  = CB_deserialize(NULL, instream);
+    VArray  *terms  = VA_deserialize(NULL, instream);
+    self = self ? self : (PhraseQuery*)VTable_Make_Obj(PHRASEQUERY);
+    return S_do_init(self, field, terms, boost);
+}
+
+bool_t
+PhraseQuery_equals(PhraseQuery *self, Obj *other)
+{
+    PhraseQuery *evil_twin = (PhraseQuery*)other;
+    if (evil_twin == self) return true;
+    if (!Obj_Is_A(other, PHRASEQUERY)) return false;
+    if (self->boost != evil_twin->boost) return false;
+    if (self->field && !evil_twin->field) return false;
+    if (!self->field && evil_twin->field) return false;
+    if (self->field && !CB_Equals(self->field, (Obj*)evil_twin->field)) 
+        return false;
+    if (!VA_Equals(evil_twin->terms, (Obj*)self->terms)) return false;
+    return true;
+}
+
+CharBuf*
+PhraseQuery_to_string(PhraseQuery *self)
+{
+    uint32_t i;
+    uint32_t num_terms = VA_Get_Size(self->terms);
+    CharBuf *retval = CB_Clone(self->field);
+    CB_Cat_Trusted_Str(retval, ":\"", 2);
+    for (i = 0; i < num_terms; i++) {
+        Obj *term = VA_Fetch(self->terms, i);
+        CharBuf *term_string = Obj_To_String(term);
+        CB_Cat(retval, term_string);
+        DECREF(term_string);
+        if (i < num_terms - 1) {
+            CB_Cat_Trusted_Str(retval, " ",  1);
+        }
+    }
+    CB_Cat_Trusted_Str(retval, "\"", 1);
+    return retval;
+}
+
+Compiler*
+PhraseQuery_make_compiler(PhraseQuery *self, Searcher *searcher, 
+                          float boost)
+{
+    if (VA_Get_Size(self->terms) == 1) {
+        // Optimize for one-term "phrases". 
+        Obj *term = VA_Fetch(self->terms, 0);
+        TermQuery *term_query = TermQuery_new(self->field, term);
+        TermCompiler *term_compiler;
+        TermQuery_Set_Boost(term_query, self->boost);
+        term_compiler = (TermCompiler*)TermQuery_Make_Compiler(term_query,
+            searcher, boost);
+        DECREF(term_query);
+        return (Compiler*)term_compiler;
+    }
+    else {
+        return (Compiler*)PhraseCompiler_new(self, searcher, boost);
+    }
+}
+
+CharBuf*
+PhraseQuery_get_field(PhraseQuery *self) { return self->field; }
+VArray*
+PhraseQuery_get_terms(PhraseQuery *self) { return self->terms; }
+
+/*********************************************************************/
+
+PhraseCompiler*
+PhraseCompiler_new(PhraseQuery *parent, Searcher *searcher, float boost)
+{
+    PhraseCompiler *self = (PhraseCompiler*)VTable_Make_Obj(PHRASECOMPILER);
+    return PhraseCompiler_init(self, parent, searcher, boost);
+}
+
+PhraseCompiler*
+PhraseCompiler_init(PhraseCompiler *self, PhraseQuery *parent, 
+                    Searcher *searcher, float boost)
+{
+    Schema     *schema = Searcher_Get_Schema(searcher);
+    Similarity *sim    = Schema_Fetch_Sim(schema, parent->field);
+    VArray     *terms  = parent->terms;
+    uint32_t i, max;
+
+    // Try harder to find a Similarity if necessary. 
+    if (!sim) { sim = Schema_Get_Similarity(schema); }
+
+    // Init. 
+    Compiler_init((Compiler*)self, (Query*)parent, searcher, sim, boost);
+
+    // Store IDF for the phrase. 
+    self->idf = 0;
+    for (i = 0, max = VA_Get_Size(terms); i < max; i++) {
+        Obj *term = VA_Fetch(terms, i);
+        int32_t doc_max  = Searcher_Doc_Max(searcher);
+        int32_t doc_freq = Searcher_Doc_Freq(searcher, parent->field, term);
+        self->idf += Sim_IDF(sim, doc_freq, doc_max);
+    }
+
+    // Calculate raw weight. 
+    self->raw_weight = self->idf * self->boost;
+
+    // Make final preparations. 
+    PhraseCompiler_Normalize(self);
+
+    return self;
+}
+
+void
+PhraseCompiler_serialize(PhraseCompiler *self, OutStream *outstream)
+{
+    Compiler_serialize((Compiler*)self, outstream);
+    OutStream_Write_F32(outstream, self->idf);
+    OutStream_Write_F32(outstream, self->raw_weight);
+    OutStream_Write_F32(outstream, self->query_norm_factor);
+    OutStream_Write_F32(outstream, self->normalized_weight);
+}
+
+PhraseCompiler*
+PhraseCompiler_deserialize(PhraseCompiler *self, InStream *instream)
+{
+    self = self ? self : (PhraseCompiler*)VTable_Make_Obj(PHRASECOMPILER);
+    Compiler_deserialize((Compiler*)self, instream);
+    self->idf               = InStream_Read_F32(instream);
+    self->raw_weight        = InStream_Read_F32(instream);
+    self->query_norm_factor = InStream_Read_F32(instream);
+    self->normalized_weight = InStream_Read_F32(instream);
+    return self;
+}
+
+bool_t
+PhraseCompiler_equals(PhraseCompiler *self, Obj *other)
+{
+    PhraseCompiler *evil_twin = (PhraseCompiler*)other;
+    if (!Obj_Is_A(other, PHRASECOMPILER)) return false;
+    if (!Compiler_equals((Compiler*)self, other)) return false;
+    if (self->idf != evil_twin->idf) return false;
+    if (self->raw_weight != evil_twin->raw_weight) return false;
+    if (self->query_norm_factor != evil_twin->query_norm_factor) return false;
+    if (self->normalized_weight != evil_twin->normalized_weight) return false;
+    return true;
+}
+
+float
+PhraseCompiler_get_weight(PhraseCompiler *self)
+{
+    return self->normalized_weight;
+}
+
+float
+PhraseCompiler_sum_of_squared_weights(PhraseCompiler *self)
+{
+    return self->raw_weight * self->raw_weight;
+}
+
+void
+PhraseCompiler_apply_norm_factor(PhraseCompiler *self, float factor)
+{
+    self->query_norm_factor = factor;
+    self->normalized_weight = self->raw_weight * self->idf * factor;
+}
+
+Matcher*
+PhraseCompiler_make_matcher(PhraseCompiler *self, SegReader *reader,
+                            bool_t need_score)
+{
+    UNUSED_VAR(need_score);
+    PhraseQuery *const parent    = (PhraseQuery*)self->parent;
+    VArray *const      terms     = parent->terms;
+    uint32_t           num_terms = VA_Get_Size(terms);
+
+    // Bail if there are no terms. 
+    if (!num_terms) return NULL;
+
+    // Bail unless field is valid and posting type supports positions. 
+    Similarity *sim     = PhraseCompiler_Get_Similarity(self);
+    Posting    *posting = Sim_Make_Posting(sim);
+    if (posting == NULL || !Obj_Is_A((Obj*)posting, SCOREPOSTING)) {
+        DECREF(posting);
+        return NULL;
+    }
+    DECREF(posting);
+
+    // Bail if there's no PostingListReader for this segment. 
+    PostingListReader *const plist_reader = (PostingListReader*)SegReader_Fetch(
+        reader, VTable_Get_Name(POSTINGLISTREADER));
+    if (!plist_reader) { return NULL; }
+
+    // Look up each term. 
+    VArray  *plists = VA_new(num_terms);
+    for (uint32_t i = 0; i < num_terms; i++) {
+        Obj *term = VA_Fetch(terms, i);
+        PostingList *plist 
+            = PListReader_Posting_List(plist_reader, parent->field, term);
+
+        // Bail if any one of the terms isn't in the index. 
+        if (!plist || !PList_Get_Doc_Freq(plist)) {
+            DECREF(plist);
+            DECREF(plists);
+            return NULL;
+        }
+        VA_Push(plists, (Obj*)plist);
+    }
+
+    Matcher *retval 
+        = (Matcher*)PhraseScorer_new(sim, plists, (Compiler*)self);
+    DECREF(plists);
+    return retval;
+}
+
+VArray*
+PhraseCompiler_highlight_spans(PhraseCompiler *self, Searcher *searcher, 
+                               DocVector *doc_vec, const CharBuf *field)
+{
+    PhraseQuery *const parent = (PhraseQuery*)self->parent;
+    VArray      *const terms  = parent->terms;
+    VArray      *const spans  = VA_new(0);
+    VArray      *term_vectors;
+    BitVector   *posit_vec;
+    BitVector   *other_posit_vec;
+    uint32_t     i;
+    const uint32_t  num_terms = VA_Get_Size(terms);
+    uint32_t     num_tvs;
+    UNUSED_VAR(searcher);
+
+    // Bail if no terms or field doesn't match. 
+    if (!num_terms) { return spans; }
+    if (!CB_Equals(field, (Obj*)parent->field)) { return spans; }
+
+    term_vectors    = VA_new(num_terms);
+    posit_vec       = BitVec_new(0);
+    other_posit_vec = BitVec_new(0);
+    for (i = 0; i < num_terms; i++) {
+        Obj *term = VA_Fetch(terms, i);
+        TermVector *term_vector 
+            = DocVec_Term_Vector(doc_vec, field, (CharBuf*)term);
+
+        // Bail if any term is missing. 
+        if (!term_vector)
+            break;
+
+        VA_Push(term_vectors, (Obj*)term_vector);
+
+        if (i == 0) {
+            // Set initial positions from first term. 
+            uint32_t j;
+            I32Array *positions = TV_Get_Positions(term_vector);
+            for (j = I32Arr_Get_Size(positions); j > 0; j--) {
+                BitVec_Set(posit_vec, I32Arr_Get(positions, j - 1));
+            }
+        }
+        else {
+            // Filter positions using logical "and". 
+            uint32_t j;
+            I32Array *positions = TV_Get_Positions(term_vector);
+
+            BitVec_Clear_All(other_posit_vec);
+            for (j = I32Arr_Get_Size(positions); j > 0; j--) {
+                int32_t pos = I32Arr_Get(positions, j - 1) - i;
+                if (pos >= 0) {
+                    BitVec_Set(other_posit_vec, pos);
+                }
+            }
+            BitVec_And(posit_vec, other_posit_vec);
+        }
+    }
+
+    // Proceed only if all terms are present. 
+    num_tvs = VA_Get_Size(term_vectors);
+    if (num_tvs == num_terms) {
+        TermVector *first_tv = (TermVector*)VA_Fetch(term_vectors, 0);
+        TermVector *last_tv  
+            = (TermVector*)VA_Fetch(term_vectors, num_tvs - 1);
+        I32Array *tv_start_positions = TV_Get_Positions(first_tv);
+        I32Array *tv_end_positions   = TV_Get_Positions(last_tv);
+        I32Array *tv_start_offsets   = TV_Get_Start_Offsets(first_tv);
+        I32Array *tv_end_offsets     = TV_Get_End_Offsets(last_tv);
+        uint32_t  terms_max          = num_terms - 1;
+        I32Array *valid_posits       = BitVec_To_Array(posit_vec);
+        uint32_t  num_valid_posits   = I32Arr_Get_Size(valid_posits);
+        uint32_t j = 0;
+        uint32_t posit_tick;
+        float weight = PhraseCompiler_Get_Weight(self);
+        i = 0;
+
+        // Add only those starts/ends that belong to a valid position. 
+        for (posit_tick = 0; posit_tick < num_valid_posits; posit_tick++) {
+            int32_t valid_start_posit = I32Arr_Get(valid_posits, posit_tick);
+            int32_t valid_end_posit   = valid_start_posit + terms_max;
+            int32_t start_offset = 0, end_offset = 0;
+            uint32_t max;
+
+            for (max = I32Arr_Get_Size(tv_start_positions); i < max; i++) {
+                if (I32Arr_Get(tv_start_positions, i) == valid_start_posit) {
+                    start_offset = I32Arr_Get(tv_start_offsets, i);
+                    break;
+                }
+            }
+            for (max = I32Arr_Get_Size(tv_end_positions); j < max; j++) {
+                if (I32Arr_Get(tv_end_positions, j) == valid_end_posit) {
+                    end_offset = I32Arr_Get(tv_end_offsets, j);
+                    break;
+                }
+            }
+
+            VA_Push(spans, (Obj*)Span_new(start_offset, 
+                end_offset - start_offset, weight) );
+
+            i++, j++;
+        }
+
+        DECREF(valid_posits);
+    }
+
+    DECREF(other_posit_vec);
+    DECREF(posit_vec);
+    DECREF(term_vectors);
+    return spans;
+}
+
+/* Copyright 2006-2010 Marvin Humphrey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * under the same terms as Perl itself.
+ */
+

Propchange: incubator/lucy/trunk/import/core/KinoSearch/Search/PhraseQuery.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/lucy/trunk/import/core/KinoSearch/Search/PhraseQuery.cfh
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/import/core/KinoSearch/Search/PhraseQuery.cfh?rev=1022422&view=auto
==============================================================================
--- incubator/lucy/trunk/import/core/KinoSearch/Search/PhraseQuery.cfh (added)
+++ incubator/lucy/trunk/import/core/KinoSearch/Search/PhraseQuery.cfh Thu Oct 14 08:48:04 2010
@@ -0,0 +1,100 @@
+parcel KinoSearch cnick Kino;
+
+/** Query matching an ordered list of terms.  
+ *
+ * PhraseQuery is a subclass of L<KinoSearch::Search::Query> for matching
+ * against an ordered sequence of terms.  
+ */
+
+class KinoSearch::Search::PhraseQuery inherits KinoSearch::Search::Query
+    : dumpable {
+
+    CharBuf       *field;
+    VArray        *terms;
+
+    inert incremented PhraseQuery*
+    new(const CharBuf *field, VArray *terms);
+
+    /**
+     * @param field The field that the phrase must occur in.
+     * @param terms The ordered array of terms that must match.
+     */
+    public inert PhraseQuery*
+    init(PhraseQuery *self, const CharBuf *field, VArray *terms);
+
+    /** Accessor for object's field attribute.
+     */
+    public CharBuf*
+    Get_Field(PhraseQuery *self);
+
+    /** Accessor for object's array of terms.
+     */
+    public VArray*
+    Get_Terms(PhraseQuery *self);
+
+    public incremented Compiler*
+    Make_Compiler(PhraseQuery *self, Searcher *searcher, float boost);
+
+    public bool_t
+    Equals(PhraseQuery *self, Obj *other);
+
+    public incremented CharBuf*
+    To_String(PhraseQuery *self);
+
+    public void
+    Serialize(PhraseQuery *self, OutStream *outstream);
+
+    public incremented PhraseQuery*
+    Deserialize(PhraseQuery *self, InStream *instream);
+
+    public void
+    Destroy(PhraseQuery *self);
+}
+
+class KinoSearch::Search::PhraseCompiler 
+    inherits KinoSearch::Search::Compiler {
+
+    float idf;
+    float raw_weight;
+    float query_norm_factor;
+    float normalized_weight;
+
+    inert incremented PhraseCompiler*
+    new(PhraseQuery *parent, Searcher *searcher, float boost);
+
+    inert PhraseCompiler*
+    init(PhraseCompiler *self, PhraseQuery *parent, Searcher *searcher, 
+         float boost);
+
+    public incremented nullable Matcher*
+    Make_Matcher(PhraseCompiler *self, SegReader *reader, bool_t need_score);
+
+    public float
+    Get_Weight(PhraseCompiler *self);
+
+    public float
+    Sum_Of_Squared_Weights(PhraseCompiler *self);
+
+    public void
+    Apply_Norm_Factor(PhraseCompiler *self, float factor);
+
+    public incremented VArray*
+    Highlight_Spans(PhraseCompiler *self, Searcher *searcher, 
+                    DocVector *doc_vec, const CharBuf *field);
+
+    public bool_t
+    Equals(PhraseCompiler *self, Obj *other);
+
+    public void
+    Serialize(PhraseCompiler *self, OutStream *outstream);
+
+    public incremented PhraseCompiler*
+    Deserialize(PhraseCompiler *self, InStream *instream);
+}
+
+/* Copyright 2006-2010 Marvin Humphrey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * under the same terms as Perl itself.
+ */
+

Added: incubator/lucy/trunk/import/core/KinoSearch/Search/PhraseScorer.c
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/import/core/KinoSearch/Search/PhraseScorer.c?rev=1022422&view=auto
==============================================================================
--- incubator/lucy/trunk/import/core/KinoSearch/Search/PhraseScorer.c (added)
+++ incubator/lucy/trunk/import/core/KinoSearch/Search/PhraseScorer.c Thu Oct 14 08:48:04 2010
@@ -0,0 +1,307 @@
+#define C_KINO_PHRASESCORER
+#define C_KINO_POSTING
+#define C_KINO_SCOREPOSTING
+#include "KinoSearch/Util/ToolSet.h"
+
+#include "KinoSearch/Search/PhraseScorer.h"
+#include "KinoSearch/Index/Posting/ScorePosting.h"
+#include "KinoSearch/Index/PostingList.h"
+#include "KinoSearch/Index/Similarity.h"
+#include "KinoSearch/Search/Compiler.h"
+
+PhraseScorer*
+PhraseScorer_new(Similarity *sim, VArray *plists, Compiler *compiler)
+{
+    PhraseScorer *self = (PhraseScorer*)VTable_Make_Obj(PHRASESCORER);
+    return PhraseScorer_init(self, sim, plists, compiler);
+
+}
+
+PhraseScorer*
+PhraseScorer_init(PhraseScorer *self, Similarity *similarity, VArray *plists,
+                  Compiler *compiler)
+{
+    Matcher_init((Matcher*)self);
+
+    // Init.
+    self->anchor_set       = BB_new(0);
+    self->phrase_freq      = 0.0;
+    self->phrase_boost     = 0.0;
+    self->first_time       = true;
+    self->more             = true;
+
+    // Extract PostingLists out of VArray into local C array for quick access.
+    self->num_elements = VA_Get_Size(plists);
+    self->plists = (PostingList**)MALLOCATE(
+        self->num_elements * sizeof(PostingList*));
+    for (size_t i = 0; i < self->num_elements; i++) {
+        PostingList *const plist = (PostingList*)CERTIFY(
+            VA_Fetch(plists, i), POSTINGLIST);
+        if (plist == NULL)
+            THROW(ERR, "Missing element %u32", i);
+        self->plists[i] = (PostingList*)INCREF(plist);
+    }
+
+    // Assign.
+    self->sim       = (Similarity*)INCREF(similarity);
+    self->compiler  = (Compiler*)INCREF(compiler);
+    self->weight    = Compiler_Get_Weight(compiler);
+
+    return self;
+}
+
+void
+PhraseScorer_destroy(PhraseScorer *self) 
+{
+    if (self->plists) {
+        for (size_t i = 0; i < self->num_elements; i++) {
+            DECREF(self->plists[i]);
+        }
+        FREEMEM(self->plists);
+    }
+    DECREF(self->sim);
+    DECREF(self->anchor_set);
+    DECREF(self->compiler);
+    SUPER_DESTROY(self, PHRASESCORER);
+}
+
+int32_t
+PhraseScorer_next(PhraseScorer *self)
+{
+    if (self->first_time) {
+        return PhraseScorer_Advance(self, 1);
+    }
+    else if (self->more) {
+        const int32_t target = PList_Get_Doc_ID(self->plists[0]) + 1;
+        return PhraseScorer_Advance(self, target);
+    }
+    else {
+        return 0;
+    }
+}
+
+int32_t
+PhraseScorer_advance(PhraseScorer *self, int32_t target) 
+{
+    PostingList **const plists       = self->plists;
+    const uint32_t      num_elements = self->num_elements;
+    int32_t             highest      = 0;
+
+    // Reset match variables to indicate no match.  New values will be
+    // assigned if a match succeeds.
+    self->phrase_freq = 0.0;
+    self->doc_id      = 0;
+
+    // Find the lowest possible matching doc ID greater than the current doc
+    // ID.  If any one of the PostingLists is exhausted, we're done.
+    if (self->first_time) {
+        self->first_time = false;
+
+        // On the first call to Advance(), advance all PostingLists.
+        for (size_t i = 0, max = self->num_elements; i < max; i++) {
+            int32_t candidate = PList_Advance(plists[i], target);
+            if (!candidate) {
+                self->more = false;
+                return 0;
+            }
+            else if (candidate > highest) {
+                // Remember the highest doc ID so far.
+                highest = candidate;
+            }
+        }
+    }
+    else {
+        // On subsequent iters, advance only one PostingList.  Its new doc ID
+        // becomes the minimum target which all the others must move up to.
+        highest = PList_Advance(plists[0], target);
+        if (highest == 0) {
+            self->more = false;
+            return 0;
+        }
+    }
+
+    // Find a doc which contains all the terms.
+    while (1) {
+        bool_t agreement = true;
+
+        // Scoot all posting lists up to at least the current minimum.
+        for (uint32_t i = 0; i < num_elements; i++) {
+            PostingList *const plist = plists[i];
+            int32_t candidate = PList_Get_Doc_ID(plist);
+
+            // Is this PostingList already beyond the minimum?  Then raise the
+            // bar for everyone else.
+            if (highest < candidate) { highest = candidate; }
+            if (target < highest)    { target = highest; }
+
+            // Scoot this posting list up.
+            if (candidate < target) {
+                candidate = PList_Advance(plist, target);
+
+                // If this PostingList is exhausted, we're done.
+                if (candidate == 0) {
+                    self->more = false;
+                    return 0;
+                }
+
+                // After calling PList_Advance(), we are guaranteed to be
+                // either at or beyond the minimum, so we can assign without
+                // checking and the minumum will either go up or stay the
+                // same.
+                highest = candidate;
+            }
+        }
+
+        // See whether all the PostingLists have managed to converge on a
+        // single doc ID.
+        for (uint32_t i = 0; i < num_elements; i++) {
+            const int32_t candidate = PList_Get_Doc_ID(plists[i]);
+            if (candidate != highest) { agreement = false; }
+        }
+
+        // If we've found a doc with all terms in it, see if they form a
+        // phrase.
+        if (agreement && highest >= target) {
+            self->phrase_freq = PhraseScorer_Calc_Phrase_Freq(self);
+            if (self->phrase_freq == 0.0) {
+                // No phrase.  Move on to another doc.
+                target += 1;
+            }
+            else {
+                // Success!
+                self->doc_id = highest;
+                return highest;
+            }
+        }
+    }
+}
+
+static INLINE uint32_t 
+SI_winnow_anchors(uint32_t *anchors_start, const uint32_t *const anchors_end,
+                  const uint32_t *candidates, const uint32_t *const candidates_end,
+                  uint32_t offset) 
+{                          
+    uint32_t *anchors = anchors_start;
+    uint32_t *anchors_found = anchors_start;
+    uint32_t target_anchor;
+    uint32_t target_candidate;
+
+    // Safety check, so there's no chance of a bad dereference.
+    if (anchors_start == anchors_end || candidates == candidates_end) {
+        return 0;
+    }
+
+    /* This function is a loop that finds terms that can continue a phrase.
+     * It overwrites the anchors in place, and returns the number remaining.
+     * The basic algorithm is to alternately increment the candidates' pointer
+     * until it is at or beyond its target position, and then increment the 
+     * anchors' pointer until it is at or beyond its target.  The non-standard
+     * form is to avoid unnecessary comparisons.  This loop has not been
+     * tested for speed, but glancing at the object code produced (objdump -S)
+     * it appears to be significantly faster than the nested loop alternative.
+     * But given the vagaries of modern processors, it merits actual
+     * testing.*/
+
+ SPIN_CANDIDATES:
+    target_candidate = *anchors + offset;
+    while (*candidates < target_candidate) {
+        if (++candidates == candidates_end) goto DONE;
+    } 
+    if (*candidates == target_candidate) goto MATCH;
+    goto SPIN_ANCHORS;  
+
+ SPIN_ANCHORS: 
+    target_anchor = *candidates - offset;
+    while (*anchors < target_anchor) { 
+        if (++anchors == anchors_end) goto DONE;
+    };
+    if (*anchors == target_anchor) goto MATCH;
+    goto SPIN_CANDIDATES;  
+
+ MATCH:       
+    *anchors_found++ = *anchors;
+    if (++anchors == anchors_end) goto DONE;
+    goto SPIN_CANDIDATES; 
+
+ DONE:
+    // Return number of anchors remaining.
+    return anchors_found - anchors_start; 
+}
+
+float
+PhraseScorer_calc_phrase_freq(PhraseScorer *self) 
+{
+    PostingList **const plists   = self->plists;
+
+    /* Create a overwriteable "anchor set" from the first posting.  
+     *
+     * Each "anchor" is a position, measured in tokens, corresponding to a a
+     * term which might start a phrase.  We start off with an "anchor set"
+     * comprised of all positions at which the first term in the phrase occurs
+     * in the field.  
+     * 
+     * There can never be more phrase matches than instances of this first
+     * term.  There may be fewer however, which we will determine by seeing
+     * whether all the other terms line up at subsequent position slots.
+     * 
+     * Every time we eliminate an anchor from the anchor set, we splice it out
+     * of the array.  So if we begin with an anchor set of (15, 51, 72) and we
+     * discover that phrases occur at the first and last instances of the
+     * first term but not the middle one, the final array will be (15, 72).
+     *
+     * The number of elements in the anchor set when we are finished winnowing
+     * is our phrase freq.
+     */
+    ScorePosting *posting = (ScorePosting*)PList_Get_Posting(plists[0]);
+    uint32_t anchors_remaining = posting->freq;
+    if (!anchors_remaining) { return 0.0f; }
+
+    size_t    amount        = anchors_remaining * sizeof(uint32_t);
+    uint32_t *anchors_start = (uint32_t*)BB_Grow(self->anchor_set, amount);
+    uint32_t *anchors_end   = anchors_start + anchors_remaining;
+    memcpy(anchors_start, posting->prox, amount);
+
+    // Match the positions of other terms against the anchor set.
+    for (uint32_t i = 1, max = self->num_elements; i < max; i++) {
+        // Get the array of positions for the next term.  Unlike the anchor
+        // set (which is a copy), these won't be overwritten.
+        ScorePosting *posting = (ScorePosting*)PList_Get_Posting(plists[i]);
+        uint32_t *candidates_start = posting->prox;
+        uint32_t *candidates_end   = candidates_start + posting->freq;
+
+        // Splice out anchors that don't match the next term.  Bail out if
+        // we've eliminated all possible anchors.
+        anchors_remaining = SI_winnow_anchors(anchors_start, anchors_end,
+            candidates_start, candidates_end, i);
+        if (!anchors_remaining) { return 0.0f; }
+
+        // Adjust end for number of anchors that remain. 
+        anchors_end = anchors_start + anchors_remaining;
+    }
+
+    // The number of anchors left is the phrase freq. 
+    return (float)anchors_remaining;
+}
+
+int32_t
+PhraseScorer_get_doc_id(PhraseScorer *self) 
+{
+    return self->doc_id;
+}
+
+float
+PhraseScorer_score(PhraseScorer *self) 
+{
+    ScorePosting *posting = (ScorePosting*)PList_Get_Posting(self->plists[0]);
+    float score = Sim_TF(self->sim, self->phrase_freq) 
+                * self->weight 
+                * posting->weight;
+    return score;
+}
+
+/* Copyright 2006-2010 Marvin Humphrey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * under the same terms as Perl itself.
+ */
+

Propchange: incubator/lucy/trunk/import/core/KinoSearch/Search/PhraseScorer.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/lucy/trunk/import/core/KinoSearch/Search/PhraseScorer.cfh
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/import/core/KinoSearch/Search/PhraseScorer.cfh?rev=1022422&view=auto
==============================================================================
--- incubator/lucy/trunk/import/core/KinoSearch/Search/PhraseScorer.cfh (added)
+++ incubator/lucy/trunk/import/core/KinoSearch/Search/PhraseScorer.cfh Thu Oct 14 08:48:04 2010
@@ -0,0 +1,53 @@
+parcel KinoSearch cnick Kino;
+
+/** Matcher for a PhraseQuery. 
+ */
+
+class KinoSearch::Search::PhraseScorer inherits KinoSearch::Search::Matcher {
+
+    int32_t         doc_id;
+    uint32_t        num_elements;
+    Similarity     *sim;
+    PostingList   **plists;
+    ByteBuf        *anchor_set;
+    float           phrase_freq;
+    float           phrase_boost;
+    Compiler       *compiler;
+    float           weight;
+    bool_t          first_time;
+    bool_t          more;
+
+    inert incremented PhraseScorer*
+    new(Similarity *similarity, VArray *posting_lists, Compiler *compiler);
+
+    inert PhraseScorer*
+    init(PhraseScorer *self, Similarity *similarity, VArray *posting_lists, 
+         Compiler *compiler);
+
+    public void
+    Destroy(PhraseScorer *self);
+
+    public int32_t
+    Next(PhraseScorer *self);
+
+    public int32_t
+    Advance(PhraseScorer *self, int32_t target);
+
+    public int32_t 
+    Get_Doc_ID(PhraseScorer *self);
+
+    public float
+    Score(PhraseScorer *self);
+
+    /** Calculate how often the phrase occurs in the current document.
+     */
+    float
+    Calc_Phrase_Freq(PhraseScorer *self);
+}
+
+/* Copyright 2006-2010 Marvin Humphrey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * under the same terms as Perl itself.
+ */
+

Added: incubator/lucy/trunk/import/core/KinoSearch/Search/PolyMatcher.c
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/import/core/KinoSearch/Search/PolyMatcher.c?rev=1022422&view=auto
==============================================================================
--- incubator/lucy/trunk/import/core/KinoSearch/Search/PolyMatcher.c (added)
+++ incubator/lucy/trunk/import/core/KinoSearch/Search/PolyMatcher.c Thu Oct 14 08:48:04 2010
@@ -0,0 +1,46 @@
+#define C_KINO_POLYMATCHER
+#include "KinoSearch/Util/ToolSet.h"
+
+#include "KinoSearch/Search/PolyMatcher.h"
+#include "KinoSearch/Index/Similarity.h"
+
+PolyMatcher*
+PolyMatcher_new(VArray *children, Similarity *sim) 
+{
+    PolyMatcher *self = (PolyMatcher*)VTable_Make_Obj(POLYMATCHER);
+    return PolyMatcher_init(self, children, sim);
+}
+
+PolyMatcher*
+PolyMatcher_init(PolyMatcher *self, VArray *children, Similarity *similarity) 
+{
+    uint32_t i;
+
+    Matcher_init((Matcher*)self);
+    self->num_kids = VA_Get_Size(children);
+    self->sim      = (Similarity*)INCREF(similarity);
+    self->children = (VArray*)INCREF(children);
+    self->coord_factors = (float*)MALLOCATE((self->num_kids + 1) * sizeof(float));
+    for (i = 0; i <= self->num_kids; i++) {
+        self->coord_factors[i] = similarity
+                               ? Sim_Coord(similarity, i, self->num_kids) 
+                               : 1.0f;
+    }
+    return self;
+}
+
+void
+PolyMatcher_destroy(PolyMatcher *self) 
+{
+    DECREF(self->children);
+    DECREF(self->sim);
+    FREEMEM(self->coord_factors);
+    SUPER_DESTROY(self, POLYMATCHER);
+}
+
+/* Copyright 2008-2010 Marvin Humphrey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * under the same terms as Perl itself.
+ */
+

Propchange: incubator/lucy/trunk/import/core/KinoSearch/Search/PolyMatcher.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/lucy/trunk/import/core/KinoSearch/Search/PolyMatcher.cfh
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/import/core/KinoSearch/Search/PolyMatcher.cfh?rev=1022422&view=auto
==============================================================================
--- incubator/lucy/trunk/import/core/KinoSearch/Search/PolyMatcher.cfh (added)
+++ incubator/lucy/trunk/import/core/KinoSearch/Search/PolyMatcher.cfh Thu Oct 14 08:48:04 2010
@@ -0,0 +1,29 @@
+parcel KinoSearch cnick Kino;
+
+/** Base class for composite scorers.
+ */
+
+class KinoSearch::Search::PolyMatcher inherits KinoSearch::Search::Matcher {
+
+    VArray       *children;
+    Similarity   *sim;
+    uint32_t      num_kids;
+    uint32_t      matching_kids;
+    float        *coord_factors;
+
+    inert incremented PolyMatcher* 
+    new(VArray *children, Similarity *similarity);
+
+    inert PolyMatcher* 
+    init(PolyMatcher *self, VArray *children, Similarity *similarity);
+
+    public void
+    Destroy(PolyMatcher *self);
+}
+
+/* Copyright 2008-2010 Marvin Humphrey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * under the same terms as Perl itself.
+ */
+

Added: incubator/lucy/trunk/import/core/KinoSearch/Search/PolyQuery.c
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/import/core/KinoSearch/Search/PolyQuery.c?rev=1022422&view=auto
==============================================================================
--- incubator/lucy/trunk/import/core/KinoSearch/Search/PolyQuery.c (added)
+++ incubator/lucy/trunk/import/core/KinoSearch/Search/PolyQuery.c Thu Oct 14 08:48:04 2010
@@ -0,0 +1,197 @@
+#define C_KINO_POLYQUERY
+#define C_KINO_POLYCOMPILER
+#include "KinoSearch/Util/ToolSet.h"
+
+#include "KinoSearch/Search/PolyQuery.h"
+#include "KinoSearch/Index/DocVector.h"
+#include "KinoSearch/Index/Similarity.h"
+#include "KinoSearch/Plan/Schema.h"
+#include "KinoSearch/Search/Searcher.h"
+#include "KinoSearch/Search/Span.h"
+#include "KinoSearch/Store/InStream.h"
+#include "KinoSearch/Store/OutStream.h"
+#include "KinoSearch/Util/Freezer.h"
+
+PolyQuery*
+PolyQuery_init(PolyQuery *self, VArray *children)
+{
+    uint32_t i;
+    const uint32_t num_kids = children ? VA_Get_Size(children) : 0;
+    Query_init((Query*)self, 1.0f);
+    self->children = VA_new(num_kids);
+    for (i = 0; i < num_kids; i++) {
+        PolyQuery_Add_Child(self, (Query*)VA_Fetch(children, i));
+    }
+    return self;
+}
+
+void
+PolyQuery_destroy(PolyQuery *self)
+{
+    DECREF(self->children);
+    SUPER_DESTROY(self, POLYQUERY);
+}
+
+void
+PolyQuery_add_child(PolyQuery *self, Query *query)
+{
+    CERTIFY(query, QUERY);
+    VA_Push(self->children, INCREF(query));
+}
+
+void
+PolyQuery_set_children(PolyQuery *self, VArray *children)
+{
+    DECREF(self->children);
+    self->children = (VArray*)INCREF(children);
+}
+
+VArray*
+PolyQuery_get_children(PolyQuery *self) { return self->children; }
+
+void
+PolyQuery_serialize(PolyQuery *self, OutStream *outstream)
+{
+    const uint32_t num_kids =  VA_Get_Size(self->children);
+    uint32_t i;
+    OutStream_Write_F32(outstream, self->boost);
+    OutStream_Write_U32(outstream, num_kids);
+    for (i = 0; i < num_kids; i++) {
+        Query *child = (Query*)VA_Fetch(self->children, i);
+        FREEZE(child, outstream);
+    }
+}
+
+PolyQuery*
+PolyQuery_deserialize(PolyQuery *self, InStream *instream)
+{
+    float boost          = InStream_Read_F32(instream);
+    uint32_t num_children   = InStream_Read_U32(instream);
+
+    if (!self) THROW(ERR, "Abstract class");
+    PolyQuery_init(self, NULL);
+    PolyQuery_Set_Boost(self, boost);
+
+    VA_Grow(self->children, num_children);
+    while (num_children--) {
+        VA_Push(self->children, THAW(instream));
+    }
+
+    return self;
+}
+
+bool_t
+PolyQuery_equals(PolyQuery *self, Obj *other)
+{
+    PolyQuery *evil_twin = (PolyQuery*)other;
+    if (evil_twin == self) return true;
+    if (!Obj_Is_A(other, POLYQUERY)) return false;
+    if (self->boost != evil_twin->boost) return false;
+    if (!VA_Equals(evil_twin->children, (Obj*)self->children)) return false;
+    return true;
+}
+
+/**********************************************************************/
+
+
+PolyCompiler*
+PolyCompiler_init(PolyCompiler *self, PolyQuery *parent, 
+                  Searcher *searcher, float boost)
+{
+    uint32_t i;
+    const uint32_t num_kids = VA_Get_Size(parent->children);
+
+    Compiler_init((Compiler*)self, (Query*)parent, searcher, NULL, boost);
+    self->children = VA_new(num_kids);
+
+    // Iterate over the children, creating a Compiler for each one. 
+    for (i = 0; i < num_kids; i++) {
+        Query *child_query = (Query*)VA_Fetch(parent->children, i);
+        float sub_boost = boost * Query_Get_Boost(child_query);
+        VA_Push(self->children, 
+            (Obj*)Query_Make_Compiler(child_query, searcher, sub_boost));
+    }
+
+    return self;
+}
+
+void
+PolyCompiler_destroy(PolyCompiler *self)
+{
+    DECREF(self->children);
+    SUPER_DESTROY(self, POLYCOMPILER);
+}
+
+float
+PolyCompiler_sum_of_squared_weights(PolyCompiler *self)
+{
+    float sum = 0;
+    uint32_t i, max;
+    float my_boost = PolyCompiler_Get_Boost(self);
+
+    for (i = 0, max = VA_Get_Size(self->children); i < max; i++) {
+        Compiler *child = (Compiler*)VA_Fetch(self->children, i);
+        sum += Compiler_Sum_Of_Squared_Weights(child);
+    }
+
+    // Compound the weight of each child. 
+    sum *= my_boost * my_boost;
+
+    return sum;
+}
+
+void
+PolyCompiler_apply_norm_factor(PolyCompiler *self, float factor)
+{
+    uint32_t i, max;
+    for (i = 0, max = VA_Get_Size(self->children); i < max; i++) {
+        Compiler *child = (Compiler*)VA_Fetch(self->children, i);
+        Compiler_Apply_Norm_Factor(child, factor);
+    }
+}
+
+VArray*
+PolyCompiler_highlight_spans(PolyCompiler *self, Searcher *searcher, 
+                            DocVector *doc_vec, const CharBuf *field)
+{
+    VArray *spans = VA_new(0);
+    uint32_t i, max;
+    for (i = 0, max = VA_Get_Size(self->children); i < max; i++) {
+        Compiler *child = (Compiler*)VA_Fetch(self->children, i);
+        VArray *child_spans = Compiler_Highlight_Spans(child, searcher,
+            doc_vec, field);
+        if (child_spans) {
+            VA_Push_VArray(spans, child_spans);
+            VA_Dec_RefCount(child_spans);
+        }
+    }
+    return spans;
+}
+
+void
+PolyCompiler_serialize(PolyCompiler *self, OutStream *outstream)
+{
+    CB_Serialize(PolyCompiler_Get_Class_Name(self), outstream);
+    VA_Serialize(self->children, outstream);
+    Compiler_serialize((Compiler*)self, outstream);
+}
+
+PolyCompiler*
+PolyCompiler_deserialize(PolyCompiler *self, InStream *instream)
+{
+    CharBuf *class_name = CB_deserialize(NULL, instream);
+    if (!self) {
+        VTable *vtable = VTable_singleton(class_name, NULL);
+        self = (PolyCompiler*)VTable_Make_Obj(vtable);
+    }
+    DECREF(class_name);
+    self->children = VA_deserialize(NULL, instream);
+    return (PolyCompiler*)Compiler_deserialize((Compiler*)self, instream);
+}
+
+/* Copyright 2006-2010 Marvin Humphrey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * under the same terms as Perl itself.
+ */
+

Propchange: incubator/lucy/trunk/import/core/KinoSearch/Search/PolyQuery.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/lucy/trunk/import/core/KinoSearch/Search/PolyQuery.cfh
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/import/core/KinoSearch/Search/PolyQuery.cfh?rev=1022422&view=auto
==============================================================================
--- incubator/lucy/trunk/import/core/KinoSearch/Search/PolyQuery.cfh (added)
+++ incubator/lucy/trunk/import/core/KinoSearch/Search/PolyQuery.cfh Thu Oct 14 08:48:04 2010
@@ -0,0 +1,83 @@
+parcel KinoSearch cnick Kino;
+
+/** Base class for composite Query objects.
+ *
+ * PolyQuery serves as a shared base class for ANDQuery, ORQuery, NOTQuery,
+ * and RequiredOptionalQuery.  All of these classes may serve as nodes in
+ * composite Query with a tree structure which may be walked.
+ */
+abstract class KinoSearch::Search::PolyQuery
+    inherits KinoSearch::Search::Query : dumpable {
+
+    VArray    *children;
+
+    /**
+     * @param children An array of child Queries.
+     */
+    public inert PolyQuery*
+    init(PolyQuery *self, VArray *children = NULL);
+
+    /** Add a child Query node.
+     */
+    public void
+    Add_Child(PolyQuery *self, Query *query);
+
+    void
+    Set_Children(PolyQuery *self, VArray *children);
+
+    VArray*
+    Get_Children(PolyQuery *self);
+
+    public void
+    Serialize(PolyQuery *self, OutStream *outstream);
+
+    public incremented PolyQuery*
+    Deserialize(PolyQuery *self, InStream *instream);
+
+    public bool_t
+    Equals(PolyQuery *self, Obj *other);
+
+    public void
+    Destroy(PolyQuery *self);
+}
+
+class KinoSearch::Search::PolyCompiler inherits KinoSearch::Search::Compiler {
+
+    VArray *children;
+
+    inert incremented PolyCompiler*
+    new(PolyQuery *parent, Searcher *searcher, float boost);
+
+    /** Initialize the Compiler, creating a Compiler child for each child
+     * Query.  Normalization is left to the subclass.
+     */
+    inert PolyCompiler*
+    init(PolyCompiler *self, PolyQuery *parent, Searcher *searcher,
+         float boost);
+
+    public float
+    Sum_Of_Squared_Weights(PolyCompiler *self);
+
+    public void
+    Apply_Norm_Factor(PolyCompiler *self, float factor);
+
+    public incremented VArray*
+    Highlight_Spans(PolyCompiler *self, Searcher *searcher, 
+                    DocVector *doc_vec, const CharBuf *field);
+
+    public void
+    Destroy(PolyCompiler *self);
+
+    public void
+    Serialize(PolyCompiler *self, OutStream *outstream);
+
+    public incremented PolyCompiler*
+    Deserialize(PolyCompiler *self, InStream *instream);
+}
+
+/* Copyright 2006-2010 Marvin Humphrey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * under the same terms as Perl itself.
+ */
+

Added: incubator/lucy/trunk/import/core/KinoSearch/Search/PolySearcher.c
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/import/core/KinoSearch/Search/PolySearcher.c?rev=1022422&view=auto
==============================================================================
--- incubator/lucy/trunk/import/core/KinoSearch/Search/PolySearcher.c (added)
+++ incubator/lucy/trunk/import/core/KinoSearch/Search/PolySearcher.c Thu Oct 14 08:48:04 2010
@@ -0,0 +1,186 @@
+#define C_KINO_POLYSEARCHER
+#include "KinoSearch/Util/ToolSet.h"
+
+#include "KinoSearch/Search/PolySearcher.h"
+
+#include "KinoSearch/Document/HitDoc.h"
+#include "KinoSearch/Index/DocVector.h"
+#include "KinoSearch/Index/PolyReader.h"
+#include "KinoSearch/Plan/Schema.h"
+#include "KinoSearch/Search/Collector.h"
+#include "KinoSearch/Search/HitQueue.h"
+#include "KinoSearch/Search/Query.h"
+#include "KinoSearch/Search/MatchDoc.h"
+#include "KinoSearch/Search/Matcher.h"
+#include "KinoSearch/Search/Searcher.h"
+#include "KinoSearch/Search/SortSpec.h"
+#include "KinoSearch/Search/TopDocs.h"
+#include "KinoSearch/Search/Compiler.h"
+
+PolySearcher*
+PolySearcher_init(PolySearcher *self, Schema *schema, VArray *searchers)
+{
+    const uint32_t num_searchers = VA_Get_Size(searchers);
+    uint32_t i;
+    int32_t *starts_array = (int32_t*)MALLOCATE(num_searchers * sizeof(int32_t));
+    int32_t doc_max = 0;
+
+    Searcher_init((Searcher*)self, schema);
+    self->searchers = (VArray*)INCREF(searchers);
+    self->starts = NULL; // Safe cleanup. 
+
+    for (i = 0; i < num_searchers; i++) {
+        Searcher *searcher 
+            = (Searcher*)CERTIFY(VA_Fetch(searchers, i), SEARCHER);
+        Schema *candidate    = Searcher_Get_Schema(searcher);
+        VTable *orig_vt      = Schema_Get_VTable(schema);
+        VTable *candidate_vt = Schema_Get_VTable(candidate);
+
+        // Confirm that searchers all use the same schema. 
+        if (orig_vt != candidate_vt) {
+            THROW(ERR, "Conflicting schemas: '%o', '%o'",
+                Schema_Get_Class_Name(schema), 
+                Schema_Get_Class_Name(candidate));
+        }
+
+        // Derive doc_max and relative start offsets. 
+        starts_array[i] = (int32_t)doc_max;
+        doc_max += Searcher_Doc_Max(searcher);
+    }
+
+    self->doc_max = doc_max;
+    self->starts  = I32Arr_new_steal(starts_array, num_searchers);
+
+    return self;
+}
+
+void
+PolySearcher_destroy(PolySearcher *self)
+{
+    DECREF(self->searchers);
+    DECREF(self->starts);
+    SUPER_DESTROY(self, POLYSEARCHER);
+}
+
+Obj*
+PolySearcher_fetch_doc(PolySearcher *self, int32_t doc_id, float score, 
+                       int32_t offset)
+{
+    uint32_t    tick       = PolyReader_sub_tick(self->starts, doc_id);
+    Searcher   *searcher   = (Searcher*)VA_Fetch(self->searchers, tick);
+    int32_t     start      = I32Arr_Get(self->starts, tick);
+    if (!searcher) { THROW(ERR, "Invalid doc id: %i32", doc_id); }
+    return Searcher_Fetch_Doc(searcher, doc_id - start, score, 
+        offset + start);
+}
+
+DocVector*
+PolySearcher_fetch_doc_vec(PolySearcher *self, int32_t doc_id)
+{
+    uint32_t    tick       = PolyReader_sub_tick(self->starts, doc_id);
+    Searcher   *searcher   = (Searcher*)VA_Fetch(self->searchers, tick);
+    int32_t     start      = I32Arr_Get(self->starts, tick);
+    if (!searcher) { THROW(ERR, "Invalid doc id: %i32", doc_id); }
+    return Searcher_Fetch_Doc_Vec(searcher, doc_id - start);
+}
+
+int32_t 
+PolySearcher_doc_max(PolySearcher *self)
+{
+    return self->doc_max;
+}
+
+uint32_t
+PolySearcher_doc_freq(PolySearcher *self, const CharBuf *field, Obj *term)
+{
+    uint32_t i, max; 
+    uint32_t doc_freq = 0;
+    for (i = 0, max = VA_Get_Size(self->searchers); i < max; i++) {
+        Searcher *searcher = (Searcher*)VA_Fetch(self->searchers, i);
+        doc_freq += Searcher_Doc_Freq(searcher, field, term);
+    }
+    return doc_freq;
+}
+
+static void
+S_modify_doc_ids(VArray *match_docs, int32_t base)
+{
+    uint32_t i, max;
+    for (i = 0, max = VA_Get_Size(match_docs); i < max; i++) {
+        MatchDoc *match_doc = (MatchDoc*)VA_Fetch(match_docs, i);
+        int32_t new_doc_id = MatchDoc_Get_Doc_ID(match_doc) + base;
+        MatchDoc_Set_Doc_ID(match_doc, new_doc_id);
+    }
+}
+
+TopDocs*
+PolySearcher_top_docs(PolySearcher *self, Query *query, uint32_t num_wanted,
+                      SortSpec *sort_spec)
+{
+    Schema   *schema      = PolySearcher_Get_Schema(self);
+    VArray   *searchers   = self->searchers;
+    I32Array *starts      = self->starts;
+    HitQueue *hit_q       = sort_spec 
+                          ? HitQ_new(schema, sort_spec, num_wanted)
+                          : HitQ_new(NULL, NULL, num_wanted);
+    uint32_t  total_hits  = 0;
+    Compiler *compiler    = Query_Is_A(query, COMPILER) 
+                          ? ((Compiler*)INCREF(query))
+                          : Query_Make_Compiler(query, (Searcher*)self,
+                                Query_Get_Boost(query));
+    uint32_t i, max;
+
+    for (i = 0, max = VA_Get_Size(searchers); i < max; i++) {
+        Searcher   *searcher   = (Searcher*)VA_Fetch(searchers, i);
+        int32_t     base       = I32Arr_Get(starts, i);
+        TopDocs    *top_docs   = Searcher_Top_Docs(searcher, 
+            (Query*)compiler, num_wanted, sort_spec);
+        VArray     *sub_match_docs = TopDocs_Get_Match_Docs(top_docs);
+        uint32_t j, jmax;
+
+        total_hits += TopDocs_Get_Total_Hits(top_docs);
+
+        S_modify_doc_ids(sub_match_docs, base);
+        for (j = 0, jmax = VA_Get_Size(sub_match_docs); j < jmax; j++) {
+            MatchDoc *match_doc = (MatchDoc*)VA_Fetch(sub_match_docs, j);
+            if (!HitQ_Insert(hit_q, INCREF(match_doc))) { break; }
+        }
+
+        DECREF(top_docs);
+    }
+
+    {
+        VArray  *match_docs = HitQ_Pop_All(hit_q);
+        TopDocs *retval     = TopDocs_new(match_docs, total_hits);
+
+        DECREF(match_docs);
+        DECREF(compiler);
+        DECREF(hit_q);
+        return retval;
+    }
+}
+
+
+void
+PolySearcher_collect(PolySearcher *self, Query *query, 
+                     Collector *collector)
+{
+    uint32_t i, max;
+    VArray *const searchers = self->searchers;
+    I32Array *starts = self->starts;
+    
+    for (i = 0, max = VA_Get_Size(searchers); i < max; i++) {
+        int32_t start = I32Arr_Get(starts, i);
+        Searcher *searcher = (Searcher*)VA_Fetch(searchers, i);
+        OffsetCollector *offset_coll = OffsetColl_new(collector, start);
+        Searcher_Collect(searcher, query, (Collector*)offset_coll);
+        DECREF(offset_coll);
+    }
+}
+
+/* Copyright 2006-2010 Marvin Humphrey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * under the same terms as Perl itself.
+ */
+

Propchange: incubator/lucy/trunk/import/core/KinoSearch/Search/PolySearcher.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/lucy/trunk/import/core/KinoSearch/Search/PolySearcher.cfh
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/import/core/KinoSearch/Search/PolySearcher.cfh?rev=1022422&view=auto
==============================================================================
--- incubator/lucy/trunk/import/core/KinoSearch/Search/PolySearcher.cfh (added)
+++ incubator/lucy/trunk/import/core/KinoSearch/Search/PolySearcher.cfh Thu Oct 14 08:48:04 2010
@@ -0,0 +1,57 @@
+parcel KinoSearch cnick Kino;
+
+/** Aggregate results from multiple searchers.
+ *
+ * The primary use for PolySearcher is to aggregate results from several
+ * remote searchers via L<KSx::Remote::SearchClient>, diffusing the cost of
+ * searching a large corpus over multiple machines.  It is also possible to
+ * aggregate results from multiple Searchers on a single machine.
+ */
+
+class KinoSearch::Search::PolySearcher 
+    inherits KinoSearch::Search::Searcher {
+    
+    VArray    *searchers;
+    I32Array  *starts;
+    int32_t    doc_max;
+
+    inert incremented PolySearcher*
+    new(Schema *schema, VArray *searchers);
+
+    /**
+     * @param schema A Schema.
+     * @param searchers An array of Searchers.
+     */
+    public inert PolySearcher*
+    init(PolySearcher *self, Schema *schema, VArray *searchers);
+
+    public void
+    Destroy(PolySearcher *self);
+
+    public int32_t
+    Doc_Max(PolySearcher *self);
+
+    public uint32_t
+    Doc_Freq(PolySearcher *self, const CharBuf *field, Obj *term);
+
+    public void
+    Collect(PolySearcher *self, Query *query, Collector *collector);
+
+    incremented TopDocs*
+    Top_Docs(PolySearcher *self, Query *query, uint32_t num_wanted,
+             SortSpec *sort_spec = NULL);
+
+    public incremented Obj*
+    Fetch_Doc(PolySearcher *self, int32_t doc_id, float score = 0.0, 
+              int32_t offset = 0);
+
+    incremented DocVector*
+    Fetch_Doc_Vec(PolySearcher *self, int32_t doc_id);
+}
+
+/* Copyright 2006-2010 Marvin Humphrey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * under the same terms as Perl itself.
+ */
+

Added: incubator/lucy/trunk/import/core/KinoSearch/Search/Query.c
URL: http://svn.apache.org/viewvc/incubator/lucy/trunk/import/core/KinoSearch/Search/Query.c?rev=1022422&view=auto
==============================================================================
--- incubator/lucy/trunk/import/core/KinoSearch/Search/Query.c (added)
+++ incubator/lucy/trunk/import/core/KinoSearch/Search/Query.c Thu Oct 14 08:48:04 2010
@@ -0,0 +1,43 @@
+#define C_KINO_QUERY
+#include "KinoSearch/Util/ToolSet.h"
+
+#include "KinoSearch/Search/Query.h"
+#include "KinoSearch/Search/Compiler.h"
+#include "KinoSearch/Search/Searcher.h"
+#include "KinoSearch/Store/InStream.h"
+#include "KinoSearch/Store/OutStream.h"
+
+Query*
+Query_init(Query *self, float boost)
+{
+    self->boost = boost;
+    ABSTRACT_CLASS_CHECK(self, QUERY);
+    return self;
+}
+
+void
+Query_set_boost(Query *self, float boost) { self->boost = boost; }
+float
+Query_get_boost(Query *self)              { return self->boost; }
+
+void
+Query_serialize(Query *self, OutStream *outstream)
+{
+    OutStream_Write_F32(outstream, self->boost);
+}
+
+Query*
+Query_deserialize(Query *self, InStream *instream)
+{
+    float boost = InStream_Read_F32(instream);
+    self = self ? self : (Query*)VTable_Make_Obj(QUERY);
+    Query_init(self, boost);
+    return self;
+}
+
+/* Copyright 2006-2010 Marvin Humphrey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * under the same terms as Perl itself.
+ */
+

Propchange: incubator/lucy/trunk/import/core/KinoSearch/Search/Query.c
------------------------------------------------------------------------------
    svn:eol-style = native