Skip to content

Commit 4d8fe87

Browse files
committed
MLE-4113 : Submit Optic fromSearch plan with BM25 scoring with Node Client
1 parent 5349420 commit 4d8fe87

File tree

2 files changed

+102
-12
lines changed

2 files changed

+102
-12
lines changed

lib/plan-builder-base.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,11 @@ function castArg(arg, funcName, paramName, argPos, paramTypes) {
122122
const value = arg[key];
123123
switch(key) {
124124
case 'scoreMethod':
125-
if (['logtfidf', 'logtf', 'simple', 'score-logtfidf', 'score-logtf', 'score-simple'].includes(value)) {
125+
if (['logtfidf', 'logtf', 'simple', 'zero', 'random', 'bm25'].includes(value)) {
126126
return true;
127127
}
128128
throw new Error(
129-
`${argLabel(funcName, paramName, argPos)} can only be logtfidf, logtf, or simple`
129+
`${argLabel(funcName, paramName, argPos)} can only be 'logtfidf', 'logtf', 'simple', 'zero', 'random' or 'bm25'`
130130
);
131131
case 'qualityWeight':
132132
if (typeof value === 'number' || value instanceof Number) {
@@ -135,6 +135,13 @@ function castArg(arg, funcName, paramName, argPos, paramTypes) {
135135
throw new Error(
136136
`${argLabel(funcName, paramName, argPos)} must be a number`
137137
);
138+
case 'bm25LengthWeight':
139+
if (typeof value === 'number' || value instanceof Number) {
140+
return true;
141+
}
142+
throw new Error(
143+
`bm25LengthWeight must be a number`
144+
);
138145
default:
139146
return false;
140147
}});

test-basic/plan-search.js

Lines changed: 93 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,20 @@ const p = marklogic.planBuilder;
2323
const pbb = require('./plan-builder-base');
2424
const execPlan = pbb.execPlan;
2525
const getResults = pbb.getResults;
26+
const assert = require('assert');
27+
const testlib = require("../etc/test-lib");
28+
let serverConfiguration = {};
2629

2730
describe('search', function() {
31+
before(function (done) {
32+
this.timeout(6000);
33+
try {
34+
testlib.findServerConfiguration(serverConfiguration);
35+
setTimeout(()=>done(), 3000);
36+
} catch(error){
37+
done(error);
38+
}
39+
});
2840
describe('accessors', function() {
2941
it('basic', function(done) {
3042
execPlan(
@@ -37,7 +49,7 @@ describe('search', function() {
3749
should(output[1].score.value).greaterThan(0);
3850
should(output[0].score.value).greaterThanOrEqual(output[1].score.value);
3951
done();
40-
}).catch(done);
52+
}).catch(error => done(error));
4153
});
4254
it('query shortcut', function(done) {
4355
execPlan(
@@ -50,7 +62,7 @@ describe('search', function() {
5062
should(output[1].score.value).greaterThan(0);
5163
should(output[0].score.value).greaterThanOrEqual(output[1].score.value);
5264
done();
53-
}).catch(done);
65+
}).catch(error => done(error));
5466
});
5567
it('columns', function(done) {
5668
execPlan(
@@ -66,7 +78,7 @@ describe('search', function() {
6678
should(output[1].fitness.value).greaterThanOrEqual(0);
6779
should(output[1].weight.value).greaterThanOrEqual(0);
6880
done();
69-
}).catch(done);
81+
}).catch(error => done(error));
7082
});
7183
it('qualifier', function(done) {
7284
execPlan(
@@ -79,7 +91,7 @@ describe('search', function() {
7991
should(output[1]['relevance.score'].value).greaterThan(0);
8092
should(output[0]['relevance.score'].value).greaterThanOrEqual(output[1]['relevance.score'].value);
8193
done();
82-
}).catch(done);
94+
}).catch(error => done(error));
8395
});
8496
it('qualified columns', function(done) {
8597
execPlan(
@@ -96,9 +108,9 @@ describe('search', function() {
96108
should(output[1]['relevance.fitness'].value).greaterThanOrEqual(0);
97109
should(output[1]['relevance.weight'].value).greaterThanOrEqual(0);
98110
done();
99-
}).catch(done);
111+
}).catch(error => done(error));
100112
});
101-
it('columns', function(done) {
113+
it('columns with options', function(done) {
102114
execPlan(
103115
p.fromSearch(p.cts.jsonPropertyValueQuery('instrument', 'trumpet'),
104116
['score', 'quality'], null, {scoreMethod:'simple', qualityWeight:0})
@@ -110,7 +122,7 @@ describe('search', function() {
110122
should(output[1].score.value).greaterThan(0);
111123
should(output[1].quality.value).greaterThanOrEqual(0);
112124
done();
113-
}).catch(done);
125+
}).catch(error => done(error));
114126
});
115127
it('with fragment id column', function(done) {
116128
execPlan(
@@ -122,7 +134,7 @@ describe('search', function() {
122134
should(output.length).equal(1);
123135
should(output[0].fragmentIdCheck.value).equal(true);
124136
done();
125-
}).catch(done);
137+
}).catch(error => done(error));
126138
});
127139
});
128140
describe('convenience', function() {
@@ -145,7 +157,7 @@ describe('search', function() {
145157
should(output[1].doc.value.musician.instrument[0]).equal('trumpet');
146158
should(output[0].score.value).greaterThanOrEqual(output[1].score.value);
147159
done();
148-
}).catch(done);
160+
}).catch(error => done(error));
149161
});
150162
it('qualified', function(done) {
151163
execPlan(
@@ -166,8 +178,79 @@ describe('search', function() {
166178
should(output[1]['relevance.doc'].value.musician.instrument[0]).equal('trumpet');
167179
should(output[0]['relevance.score'].value).greaterThanOrEqual(output[1]['relevance.score'].value);
168180
done();
169-
}).catch(done);
181+
}).catch(error => done(error));
170182
});
171183
// console.log(JSON.stringify(output, null, 2));
172184
});
185+
186+
describe('tests for new scoring methods - bm25, random and zero.', function() {
187+
before(function (done) {
188+
if(serverConfiguration.serverVersion < 12) {
189+
this.skip();
190+
}
191+
done();
192+
});
193+
194+
it('should search documents with bm25', function(done) {
195+
execPlan(
196+
p.fromSearch(p.cts.jsonPropertyValueQuery('instrument', 'trumpet'),
197+
['score', 'quality'], null, { scoreMethod: 'bm25', bm25LengthWeight: 0.25 })
198+
).then(function(response) {
199+
assert(response.columns != null)
200+
assert(response.rows != null)
201+
done();
202+
}).catch(error => done(error));
203+
});
204+
205+
it('should throw error with invalid bm25LengthWeight', function(done) {
206+
execPlan(
207+
p.fromSearch(p.cts.jsonPropertyValueQuery('instrument', 'trumpet'),
208+
['score', 'quality'], null, { scoreMethod: 'bm25', bm25LengthWeight: 99 })
209+
).catch(error => {
210+
try{
211+
assert(error.body.errorResponse.message.toString().includes('Invalid option "bm25-length-weight=99'));
212+
done();
213+
} catch(error){
214+
done(error);
215+
}
216+
});
217+
});
218+
219+
it('should throw error with string values for bm25LengthWeight', function(done) {
220+
try {
221+
execPlan(
222+
p.fromSearch(p.cts.jsonPropertyValueQuery('instrument', 'trumpet'),
223+
['score', 'quality'], null, { scoreMethod: 'bm25', bm25LengthWeight: 'abc' })
224+
);
225+
} catch(error){
226+
assert(error.message.toString().includes('bm25LengthWeight must be a number'));
227+
done();
228+
}
229+
});
230+
231+
it('should search documents with zero scoring method', function(done) {
232+
execPlan(
233+
p.fromSearch(p.cts.jsonPropertyValueQuery('instrument', 'trumpet'),
234+
['score', 'quality'], null, { scoreMethod: 'zero'})
235+
).then(function(response) {
236+
assert(response.columns != null)
237+
assert(response.rows != null)
238+
for(let i=0; i<response.rows.length; i++){
239+
assert(response.rows[i].score.value == 0)
240+
}
241+
done();
242+
}).catch(error => done(error));
243+
});
244+
245+
it('should search documents with random scoring method', function(done) {
246+
execPlan(
247+
p.fromSearch(p.cts.jsonPropertyValueQuery('instrument', 'trumpet'),
248+
['score', 'quality'], null, { scoreMethod: 'random'})
249+
).then(function(response) {
250+
assert(response.columns != null)
251+
assert(response.rows != null)
252+
done();
253+
}).catch(error => done(error));
254+
});
255+
});
173256
});

0 commit comments

Comments
 (0)