-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.go
125 lines (114 loc) · 2.97 KB
/
search.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package main
import (
"fmt"
"strings"
"github.com/blevesearch/bleve"
"github.com/knakk/kbp/rdf"
"github.com/knakk/kbp/rdf/memory"
"github.com/knakk/mormor/entity"
)
// doc is a document representing a resource that can be indexed and retrieved
type doc struct {
Title string
ID string
Abstract string
Type string
}
type searchResults struct {
NumHits int
Hits []doc
}
type searchService struct {
Index bleve.Index
langs []string
}
func newSearchService(langs string) *searchService {
index, err := bleve.NewMemOnly(bleve.NewIndexMapping())
if err != nil {
panic(err)
}
return &searchService{
Index: index,
langs: strings.Split(langs, ","),
}
}
func (s *searchService) indexResourceFromGraph(uri rdf.NamedNode, g *memory.Graph) error {
var e entity.Entity
switch entity.TypeFromURI(uri) {
case entity.TypePerson:
var p entity.Person
if err := g.Decode(&p, uri, rdf.NewNamedNode(""), s.langs); err != nil {
return fmt.Errorf("indexResourceFromGraph decode %s as Person error: %v", uri, err)
}
p.Process()
e = &p
/*case entity.TypePublication:
var p entity.PublicationWithWork
if err := g.Decode(&p, uri, rdf.NewNamedNode("")); err != nil {
return fmt.Errorf("indexResourceFromGraph decode %s as Publication error: %v", uri, err)
}
e = p
*/
case entity.TypeWork:
var w entity.Work
if err := g.Decode(&w, uri, rdf.NewNamedNode(""), s.langs); err != nil {
return fmt.Errorf("indexResourceFromGraph decode %s as Work error: %v", uri, err)
}
w.Process()
e = &w
default:
panic("TODO indexResourceFromGraph " + entity.TypeFromURI(uri).String())
}
d := doc{
Title: e.CanonicalTitle(),
Abstract: e.Abstract(),
ID: e.ID(),
Type: e.EntityType().String(),
}
return s.Index.Index(uri.Name(), d)
}
func (s *searchService) query(idx entity.Type, q string) (searchResults, error) {
query := bleve.NewQueryStringQuery("+Type:" + idx.String() + " +" + q)
req := bleve.NewSearchRequest(query)
res, err := s.Index.Search(req)
if err != nil {
return searchResults{}, err
}
return s.parseSearchResults(res)
}
func (s *searchService) queryAll(q string) (searchResults, error) {
query := bleve.NewQueryStringQuery(q)
req := bleve.NewSearchRequest(query)
res, err := s.Index.Search(req)
if err != nil {
return searchResults{}, err
}
return s.parseSearchResults(res)
}
func (s *searchService) parseSearchResults(res *bleve.SearchResult) (searchResults, error) {
parsed := searchResults{
NumHits: int(res.Total),
Hits: make([]doc, 0, res.Hits.Len()),
}
for _, hit := range res.Hits {
stored, err := s.Index.Document(hit.ID)
if err != nil {
return parsed, err
}
var d doc
for _, field := range stored.Fields {
switch field.Name() {
case "ID":
d.ID = string(field.Value())
case "Title":
d.Title = string(field.Value())
case "Abstract":
d.Abstract = string(field.Value())
case "Type":
d.Type = string(field.Value())
}
}
parsed.Hits = append(parsed.Hits, d)
}
return parsed, nil
}