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()