예제 #1
0
파일: search.go 프로젝트: rectang/golucy
// This will need to be a bit more generic,
// but for testing this will work fine.
func (search *Search) GetSearcher() IndexReader {
	idxLocation := cb_newf(search.Location)
	search.lucySearcher = C.LucyIxSearcherNew(idxLocation)
	C.DECREF(idxLocation)
	return func(q string, field string, offset, limit uint) (uint, []string) {
		query := cb_new_from_utf8(q)
		getField := cb_newf(field)
		hits := C.LucyIxSearcherHits(search.lucySearcher, query, C.uint32_t(offset), C.uint32_t(limit), nil)
		totalNumHits := uint(C.LucyHitsTotal(hits))
		requestedNumHits := minUInt(limit, totalNumHits)
		results := make([]string, requestedNumHits)
		var hit *C.LucyHitDoc
		for i := uint(0); i < requestedNumHits; i++ {
			hit = C.LucyHitsNext(hits)
			if hit == nil {
				break
			}
			value_cb := C.LucyHitDocExtract(hit, getField, nil) // do i need to free this
			value := cb_ptr2char(value_cb)                      // do i need to free this
			results[i] = C.GoString(value)
			C.DECREF(hit)
		}
		C.DECREF(query)
		C.DECREF(getField)
		C.DECREF(hits)
		return totalNumHits, results
	}
}
예제 #2
0
파일: searcher.go 프로젝트: postfix/golucy
func (ixReader *IndexReader) Search(query *Query, offset, limit uint, idField string, contentField string, includeMatchedTerms bool) (uint, []*SearchResult) {
	// Should probably have some sort
	// of `Results` object/iterator so that we don't have to specify
	// offset/limit and where I can attach matched terms to the result.
	lIdField, lContentField := cb_newf(idField), cb_newf(contentField) // total hack, need to return more than one field
	defer C.DECREF(lIdField)
	defer C.DECREF(lContentField)
	hits := C.LucyIxSearcherHits(ixReader.lucySearcher, query.lucyQuery, C.uint32_t(offset), C.uint32_t(limit), nil)
	defer C.DECREF(hits)
	totalNumHits := uint(C.LucyHitsTotal(hits))
	num2Return := minUInt(limit, totalNumHits)
	results := make([]*SearchResult, num2Return)
	var hit *C.LucyHitDoc
	compiler := C.LucyQueryMakeCompiler(query.lucyQuery, ixReader.lucySearcher, 1.0, false)
	defer C.DECREF(compiler)

	matchedTerms := func(docId C.int32_t, result *SearchResult) {
		docVec := C.LucyIxSearchFetchDocVec(ixReader.lucySearcher, docId)
		defer C.DECREF(docVec)
		spans := C.LucyCompilerHighlightSpans(compiler, ixReader.lucySearcher, docVec, lContentField)
		defer C.DECREF(spans)
		spanCnt := C.VaGetSize(spans)
		if spanCnt == 0 {
			// should never get here, but just in case...
			return
		}
		result.MatchedTerms = make([]string, spanCnt)
		var i C.uint32_t
		for i = 0; i < spanCnt; i++ {
			span := C.VaFetch(spans, i)
			offset := C.LucySpanGetOffset(span)
			length := C.LucySpanGetLength(span)
			result.MatchedTerms[i] = string([]rune(result.Text)[offset : offset+length])
		}
		// make terms unique?
		result.MatchedTerms = set(result.MatchedTerms)
	}
	var i uint
	for i = 0; i < num2Return; i++ {
		hit = C.LucyHitsNext(hits)
		if hit == nil {
			break
		}
		docId := C.LucyHitDocGetDocId(hit)
		contentValue := cb_ptr2char(C.LucyHitDocExtract(hit, lContentField, nil)) // do i need to free this
		idValue := cb_ptr2char(C.LucyHitDocExtract(hit, lIdField, nil))           // do i need to free this
		results[i] = &SearchResult{
			Id:    C.GoString(idValue),
			Text:  C.GoString(contentValue),
			Score: float32(C.LucyHitDocGetScore(hit)),
		}
		if includeMatchedTerms {
			matchedTerms(docId, results[i])
		}
		C.DECREF(hit)
	}
	return totalNumHits, results
}