2 #include <node_object_wrap.h>
5 #include <zettair/def.h>
6 #include <zettair/index.h>
10 static v8::Local<v8::Object> index_result_to_object(
12 struct index_result* result
14 static v8::Local<v8::Object> index_results_to_object(
16 struct index_result* results,
17 unsigned int num_results,
18 double/*unsigned long int*/ total_results
21 class IndexObject : public node::ObjectWrap {
23 static void Init(v8::Local<v8::Object> exports);
28 explicit IndexObject(struct index* idx0);
31 static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
32 static void Search(const v8::FunctionCallbackInfo<v8::Value>& args);
33 static v8::Persistent<v8::Function> constructor;
36 v8::Persistent<v8::Function> IndexObject::constructor;
38 IndexObject::IndexObject(struct index* idx0) : idx(idx0) {
41 IndexObject::~IndexObject() {
44 void IndexObject::Init(v8::Local<v8::Object> exports) {
45 v8::Isolate* isolate = exports->GetIsolate();
47 // Prepare constructor template
48 v8::Local<v8::FunctionTemplate> tpl =
49 v8::FunctionTemplate::New(isolate, New);
50 tpl->SetClassName(v8::String::NewFromUtf8(isolate, "Index"));
51 tpl->InstanceTemplate()->SetInternalFieldCount(1);
54 NODE_SET_PROTOTYPE_METHOD(tpl, "search", Search);
56 constructor.Reset(isolate, tpl->GetFunction());
58 v8::String::NewFromUtf8(isolate, "Index"),
63 void IndexObject::New(const v8::FunctionCallbackInfo<v8::Value>& args) {
64 v8::Isolate* isolate = args.GetIsolate();
66 if (args.IsConstructCall()) {
67 // Invoked as constructor: `new Index(...)`
68 v8::String::Utf8Value prefix(args[0]);
69 struct index* idx = NULL;;
70 int lopts = INDEX_LOAD_NOOPT;
71 struct index_load_opt lopt;
73 lopts |= INDEX_LOAD_IGNORE_VERSION; /* quick hack */
77 args[0]->IsString() ? *prefix : "index",
84 isolate->ThrowException(
85 v8::String::NewFromUtf8(isolate, "Unable to load index")
89 IndexObject* obj = new IndexObject(idx);
90 obj->Wrap(args.This());
91 args.GetReturnValue().Set(args.This());
93 // Invoked as plain function `Index(...)`, turn into construct call.
95 v8::Local<v8::Value> argv[argc] = { args[0] };
96 v8::Local<v8::Context> context = isolate->GetCurrentContext();
97 v8::Local<v8::Function> cons =
98 v8::Local<v8::Function>::New(isolate, constructor);
99 v8::Local<v8::Object> result =
100 cons->NewInstance(context, argc, argv).ToLocalChecked();
101 args.GetReturnValue().Set(result);
105 void IndexObject::Search(const v8::FunctionCallbackInfo<v8::Value>& args) {
106 v8::Isolate* isolate = args.GetIsolate();
108 v8::String::Utf8Value query(args[0]);
109 v8::String::Utf8Value optType(args[3]);
110 v8::Local<v8::Array> optArgsTuple;
111 if (args[4]->IsArray())
112 optArgsTuple = args[4].As<v8::Array>();
113 unsigned long startdoc = args[1]->IntegerValue();
114 unsigned long len = args[2]->IntegerValue();
115 IndexObject* Index = node::ObjectWrap::Unwrap<IndexObject>(args.Holder());
116 struct index_result* result;
117 unsigned int results;
118 double/*unsigned long int*/ total_results;
120 unsigned int accumulator_limit = args[5]->Uint32Value();
121 int opts = INDEX_SEARCH_NOOPT;
122 struct index_search_opt opt;
124 opt.u.okapi_k3.k1 = 1.2;
125 opt.u.okapi_k3.k3 = 1e10;
126 opt.u.okapi_k3.b = 0.75;
129 (result = (struct index_result*)malloc(sizeof(*result) * len)) == NULL
131 isolate->ThrowException(
132 v8::String::NewFromUtf8(isolate, "Unable to allocate results")
136 if (args[3]->IsString()) {
137 if (strcmp(*optType, "COSINE") == 0) {
138 opts = INDEX_SEARCH_COSINE_RANK;
139 } else if (strcmp(*optType, "OKAPI") == 0) {
140 opts = INDEX_SEARCH_OKAPI_RANK;
141 } else if (strcmp(*optType, "OKAPI_K3") == 0) {
142 if (optArgsTuple.IsEmpty()) {
143 isolate->ThrowException(
144 v8::String::NewFromUtf8(isolate, "Must supply args to search type")
149 opts = INDEX_SEARCH_OKAPI_RANK;
150 opt.u.okapi_k3.k1 = optArgsTuple->Get(0)->IntegerValue();
151 opt.u.okapi_k3.k3 = optArgsTuple->Get(1)->IntegerValue();
152 opt.u.okapi_k3.b = optArgsTuple->Get(2)->IntegerValue();
153 } else if (strcmp(*optType, "HAWKAPI") == 0) {
154 if (optArgsTuple.IsEmpty()) {
155 isolate->ThrowException(
156 v8::String::NewFromUtf8(isolate, "Must supply args to search type")
161 opts = INDEX_SEARCH_HAWKAPI_RANK;
162 opt.u.hawkapi.alpha = optArgsTuple->Get(0)->IntegerValue();
163 opt.u.hawkapi.k3 = optArgsTuple->Get(1)->IntegerValue();
164 } else if (strcmp(*optType, "DIRICHLET") == 0) {
165 opts = INDEX_SEARCH_DIRICHLET_RANK;
166 if (optArgsTuple.IsEmpty() || optArgsTuple->Length() == 0)
167 opt.u.dirichlet.mu = 2500.0;
169 opt.u.dirichlet.mu = optArgsTuple->Get(0)->NumberValue();
171 isolate->ThrowException(
172 v8::String::NewFromUtf8(isolate, "Unknown search type")
178 if (accumulator_limit != 0) {
179 opts |= INDEX_SEARCH_ACCUMULATOR_LIMIT;
180 opt.accumulator_limit = accumulator_limit;
183 opts |= INDEX_SEARCH_SUMMARY_TYPE;
184 opt.summary_type = INDEX_SUMMARISE_CAPITALISE;
186 if (!index_search(Index->idx, *query, startdoc, len,
187 result, &results, &total_results, &est, opts, &opt)) {
189 snprintf(err_buf, 1024, "Unable to perform search for query '%s'; "
190 "system error is '%s'\n", *query, strerror(errno));
191 isolate->ThrowException(
192 v8::String::NewFromUtf8(isolate, err_buf)
197 args.GetReturnValue().Set(
198 index_results_to_object(isolate, result, results, total_results)
204 static v8::Local<v8::Object> index_result_to_object(
205 v8::Isolate* isolate,
206 struct index_result* result
208 v8::EscapableHandleScope handle_scope(isolate);
209 v8::Local<v8::Object> result_object = v8::Object::New(isolate);
211 v8::String::NewFromUtf8(isolate, "docno"),
212 v8::Integer::New(isolate, result->docno)
215 v8::String::NewFromUtf8(isolate, "score"),
216 v8::Number::New(isolate, result->score)
219 v8::String::NewFromUtf8(isolate, "summary"),
220 v8::String::NewFromUtf8(isolate, result->summary)
223 v8::String::NewFromUtf8(isolate, "title"),
224 v8::String::NewFromUtf8(isolate, result->title)
227 v8::String::NewFromUtf8(isolate, "auxiliary"),
228 v8::String::NewFromUtf8(isolate, result->auxilliary)
230 return handle_scope.Escape(result_object);
233 static v8::Local<v8::Object> index_results_to_object(
234 v8::Isolate* isolate,
235 struct index_result* results,
236 unsigned int num_results,
237 double/*unsigned long int*/ total_results
239 v8::EscapableHandleScope handle_scope(isolate);
240 v8::Local<v8::Object> results_object = v8::Object::New(isolate);
241 v8::Local<v8::Array> results_array = v8::Array::New(isolate, num_results);
242 for (unsigned int i = 0; i < num_results; ++i)
243 results_array->Set(i, index_result_to_object(isolate, results + i));
245 v8::String::NewFromUtf8(isolate, "results"),
249 v8::String::NewFromUtf8(isolate, "total_results"),
250 v8::Number::New(isolate, total_results)
252 return handle_scope.Escape(results_object);
255 void InitAll(v8::Local<v8::Object> exports) {
256 IndexObject::Init(exports);
259 NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll)