Allow diff doc types in Hits.Next() Go binding.

Allow 3 different types of object to retrieve fields via Next()
*   Go struct
*   Lucy HitDoc
*   map[string]interface{}


Project: http://git-wip-us.apache.org/repos/asf/lucy/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy/commit/1b97823d
Tree: http://git-wip-us.apache.org/repos/asf/lucy/tree/1b97823d
Diff: http://git-wip-us.apache.org/repos/asf/lucy/diff/1b97823d

Branch: refs/heads/master
Commit: 1b97823de7df7a09826d16070d72dd1922b73072
Parents: 853cf86
Author: Marvin Humphrey <[email protected]>
Authored: Fri Sep 25 20:01:24 2015 -0700
Committer: Marvin Humphrey <[email protected]>
Committed: Mon Sep 28 12:54:39 2015 -0700

----------------------------------------------------------------------
 go/lucy/search.go      | 73 ++++++++++++++++++---------------------------
 go/lucy/search_test.go | 24 +++++++++++++++
 2 files changed, 53 insertions(+), 44 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/1b97823d/go/lucy/search.go
----------------------------------------------------------------------
diff --git a/go/lucy/search.go b/go/lucy/search.go
index 514c2eb..a8bab6f 100644
--- a/go/lucy/search.go
+++ b/go/lucy/search.go
@@ -17,6 +17,9 @@
 package lucy
 
 /*
+
+#define C_LUCY_HITS
+
 #include "Lucy/Search/Collector.h"
 #include "Lucy/Search/Collector/SortCollector.h"
 #include "Lucy/Search/Hits.h"
@@ -26,6 +29,7 @@ package lucy
 #include "Lucy/Search/ANDQuery.h"
 #include "Lucy/Search/ORQuery.h"
 #include "Lucy/Search/ANDMatcher.h"
+#include "Lucy/Search/MatchDoc.h"
 #include "Lucy/Search/ORMatcher.h"
 #include "Lucy/Search/SeriesMatcher.h"
 #include "Lucy/Search/SortRule.h"
@@ -46,9 +50,6 @@ float32_set(float *floats, size_t i, float value) {
 
 */
 import "C"
-import "fmt"
-import "reflect"
-import "strings"
 import "unsafe"
 
 import 
"git-wip-us.apache.org/repos/asf/lucy-clownfish.git/runtime/go/clownfish"
@@ -135,52 +136,36 @@ func (obj *PolySearcherIMP) Hits(query interface{}, 
offset uint32, numWanted uin
        return doHits(obj, query, offset, numWanted, sortSpec)
 }
 
-func (obj *HitsIMP) Next(hit interface{}) bool {
-       self := ((*C.lucy_Hits)(unsafe.Pointer(obj.TOPTR())))
-       // TODO: accept a HitDoc object and populate score.
-
-       // Get reflection value and type for the supplied struct.
-       var hitValue reflect.Value
-       if reflect.ValueOf(hit).Kind() == reflect.Ptr {
-               temp := reflect.ValueOf(hit).Elem()
-               if temp.Kind() == reflect.Struct {
-                       if temp.CanSet() {
-                               hitValue = temp
-                       }
-               }
-       }
-       if hitValue == (reflect.Value{}) {
-               mess := fmt.Sprintf("Arg not writeable struct pointer: %v",
-                       reflect.TypeOf(hit))
-               obj.err = clownfish.NewErr(mess)
-               return false
-       }
+type setScorer interface {
+       SetScore(float32)
+}
 
-       var docC *C.lucy_HitDoc
-       errCallingNext := clownfish.TrapErr(func() {
-               docC = C.LUCY_Hits_Next(self)
-       })
-       if errCallingNext != nil {
-               obj.err = errCallingNext
-               return false
-       }
-       if docC == nil {
-               return false
-       }
-       defer C.cfish_dec_refcount(unsafe.Pointer(docC))
+func (h *HitsIMP) Next(hit interface{}) bool {
+       self := (*C.lucy_Hits)(clownfish.Unwrap(h, "h"))
+       ivars := C.lucy_Hits_IVARS(self)
+       matchDoc := (*C.lucy_MatchDoc)(unsafe.Pointer(
+               C.CFISH_Vec_Fetch(ivars.match_docs, C.size_t(ivars.offset))))
+       ivars.offset += 1
 
-       fields := fetchDocFields((*C.lucy_Doc)(unsafe.Pointer(docC)))
-       for key, val := range fields {
-               stringVal := val.(string) // TODO type switch
-               match := func(name string) bool {
-                       return strings.EqualFold(key, name)
+       if matchDoc == nil {
+               // Bail if there aren't any more *captured* hits.  (There may be
+               // more total hits.)
+               return false
+       } else {
+               // Lazily fetch HitDoc, set score.
+               searcher := clownfish.WRAPAny(unsafe.Pointer(C.cfish_incref(
+                       unsafe.Pointer(ivars.searcher)))).(Searcher)
+               docID := int32(C.LUCY_MatchDoc_Get_Doc_ID(matchDoc))
+               err := searcher.ReadDoc(docID, hit)
+               if err != nil {
+                       h.err = err
+                       return false
                }
-               structField := hitValue.FieldByNameFunc(match)
-               if structField != (reflect.Value{}) {
-                       structField.SetString(stringVal)
+               if ss, ok := hit.(setScorer); ok {
+                       
ss.SetScore(float32(C.LUCY_MatchDoc_Get_Score(matchDoc)))
                }
+               return true
        }
-       return true
 }
 
 func (obj *HitsIMP) Error() error {

http://git-wip-us.apache.org/repos/asf/lucy/blob/1b97823d/go/lucy/search_test.go
----------------------------------------------------------------------
diff --git a/go/lucy/search_test.go b/go/lucy/search_test.go
index d0668ae..ae4c352 100644
--- a/go/lucy/search_test.go
+++ b/go/lucy/search_test.go
@@ -438,6 +438,30 @@ func TestHitsBasics(t *testing.T) {
        }
 }
 
+func TestHitsNext(t *testing.T) {
+       index := createTestIndex("a x", "a y", "a z", "b")
+       searcher, _ := OpenIndexSearcher(index)
+       hits, _ := searcher.Hits("a", 0, 10, nil)
+       docDoc := NewHitDoc(0, -1.0)
+       docStruct := &simpleTestDoc{}
+       docMap := make(map[string]interface{})
+       if !hits.Next(docDoc) || !hits.Next(docStruct) || !hits.Next(docMap) {
+               t.Errorf("Hits.Next returned false: %v", hits.Error())
+       }
+       if hits.Next(&simpleTestDoc{}) {
+               t.Error("Hits iterator should be exhausted");
+       }
+       if docDoc.Extract("content").(string) != "a x" {
+               t.Error("Next with Doc object yielded bad data")
+       }
+       if docStruct.Content != "a y" {
+               t.Error("Next with struct yielded bad data")
+       }
+       if docMap["content"].(string) != "a z" {
+               t.Error("Next with map yielded bad data")
+       }
+}
+
 func TestSortSpecBasics(t *testing.T) {
        folder := NewRAMFolder("")
        schema := NewSchema()

Reply via email to