Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions src/document/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ Document.prototype.search = function(query, limit, options, _promises){
let result = [];
let result_field = [];
let pluck, enrich, merge, suggest, boost, cache;
let field, tag, offset, count = 0, resolve = true, highlight;
let field, tag, offset, count = 0, resolve = true, highlight, merge_limit = 0;

if(options){

Expand Down Expand Up @@ -123,6 +123,10 @@ Document.prototype.search = function(query, limit, options, _promises){
limit = options.limit || limit;
offset = options.offset || 0;
limit || (limit = (resolve ? 100 : 0));
// per-field options below may override "limit" for individual fields,
// so the overall limit requested by the caller has to be captured here
// to cap the merged result correctly.
merge_limit = limit;

if(tag && (!SUPPORT_PERSISTENT || !this.db || !_promises)){

Expand Down Expand Up @@ -550,7 +554,7 @@ Document.prototype.search = function(query, limit, options, _promises){
result = highlight_fields(/** @type {string} */ (query), result, self.index, pluck, highlight);
}
return merge
? merge_fields(result)
? merge_fields(result, merge_limit)
: /** @type {DocumentSearchResults} */ (result);
});
}
Expand All @@ -559,7 +563,7 @@ Document.prototype.search = function(query, limit, options, _promises){
result = highlight_fields(/** @type {string} */ (query), result, this.index, pluck, highlight);
}
return merge
? merge_fields(result)
? merge_fields(result, merge_limit)
: /** @type {DocumentSearchResults} */ (result);
}

Expand All @@ -570,14 +574,15 @@ Document.prototype.search = function(query, limit, options, _promises){

/**
* @param {DocumentSearchResults} fields
* @param {number=} limit
* @return {MergedDocumentSearchResults}
*/
function merge_fields(fields){
function merge_fields(fields, limit){
/** @type {MergedDocumentSearchResults} */
const final = [];
const group_field = create_object();
const group_highlight = create_object();
for(let i = 0, field, key, res, id, entry, tmp, highlight; i < fields.length; i++){
outer: for(let i = 0, field, key, res, id, entry, tmp, highlight; i < fields.length; i++){
field = fields[i];
key = field.field;
res = field.result;
Expand All @@ -589,6 +594,12 @@ function merge_fields(fields){
: id = entry["id"];
tmp = group_field[id];
if(!tmp){
// results are merged across fields, so the per-field limit
// applied earlier does not cap the merged total; stop once
// the overall requested limit has been reached
if(limit && final.length === limit){
break outer;
}
entry["field"] = group_field[id] = [key];
final.push(/** @type {!MergedDocumentSearchEntry} */ (entry));
}
Expand Down
36 changes: 36 additions & 0 deletions test/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,42 @@ if(!build_light) describe("Document (Multi-Field Search)", function(){
]);
});

it("Should cap merged results at the requested limit", function(){

const document = new Document({
document: {
id: "id",
field: [
"name_1",
"name_2",
"name_3"
]
}
});

const names = ["foo", "bar"];

// each field matches a different, non-overlapping half of the ids,
// so merging the per-field results (each already capped at "limit")
// produces more unique ids than "limit" unless the merge step
// re-applies the cap itself
for(let i = 0; i < 30; i++){
document.add({
id: i,
name_1: names[i % 2],
name_2: names[(i + 1) % 2],
name_3: names[i % 2]
});
}

const result = document.search("foo", {
merge: true,
limit: 10
});

expect(result.length).to.equal(10);
});

it("Using BigInt", function(){

const document = new Document({
Expand Down