How to limit the result count from the query?
hoogw opened this issue · comments
Is there something like this, return max 10 item by
`tree.search(
{minX,..... maxY:...},
10).`
It is same idea on sql 'top'
`select top 100, * from table`
It's right in the readme, pal: https://github.com/mourner/rbush#k-nearest-neighbors
It's right in the readme, pal: https://github.com/mourner/rbush#k-nearest-neighbors
No, it is not related to my question.
Is there something like this, return max 10 item by
`tree.search(
{minX,..... maxY:...},
10).`
KNN is searching for 10 around a point,
What I want is for 10 within a bbox, in KNN, how to implement a query select top 10 intersect a bbox? KNN can only query around a point, not within a bounding box.
I add limit as
tree.search(bbox,limit)
will return max limit count:
rbush.js do following modification:
I test it, it works great!!!!
Can you put a new request to add this new feature? It will be very useful for many people.
Because googlemaps api will freeze when displaying over 5000 feature,
I must limit the search results size under (for example 300 feature) for smooth(googlemap api) interaction.
`RBush.prototype.search = function search (bbox, limit) {
var node = this.data;
var result = [];
if (!intersects(bbox, node)) { return result; }
var toBBox = this.toBBox;
var nodesToSearch = [];
while (node) {
for (var i = 0; i < node.children.length; i++) {
// limit the result size
if (result.length > limit) { return result;}
var child = node.children[i];
var childBBox = node.leaf ? toBBox(child) : child;
if (intersects(bbox, childBBox)) {
if (node.leaf) { result.push(child); }
else if (contains(bbox, childBBox)) { this._all(child, result); }
else { nodesToSearch.push(child); }
}
}
node = nodesToSearch.pop();
}
return result;
};`
@hoogw you also need to add the limit to _all
so that it doesn't add more than the limit to the result.
I think it's fine to simply augment the method on the application side, no need to have this option in the core.
@hoogw you also need to add the limit to
_all
so that it doesn't add more than the limit to the result.I think it's fine to simply augment the method on the application side, no need to have this option in the core.
@mourner mourner
I am not sure is this correct? Do I have to put a big number 99999999?
RBush.prototype.all = function all () { return this._all(this.data, [], 99999999); };
`if (intersects(bbox, childBBox)) {
if (node.leaf) { result.push(child); }
else if (contains(bbox, childBBox)) { this._all(child, result, limit); }
else { nodesToSearch.push(child); }
}
`
`RBush.prototype._all = function _all (node, result, limit) {
var nodesToSearch = [];
while (node) {
if (result.length > limit) { return result;}
if (node.leaf) { result.push.apply(result, node.children); }
else { nodesToSearch.push.apply(nodesToSearch, node.children); }
node = nodesToSearch.pop();
}
return result;
};`
@mourner mourner
what the all() function use for?
Is my modification Safe?
Hope my modification NOT break other things. This is my big concern.
RBush.prototype.all = function all () { return this._all(this.data, [], 0); };
` //add limit result size
RBush.prototype._all = function _all (node, result, limit) {
var nodesToSearch = [];
while (node) {
//add limit result size
// limit = 0 means, no limit
if (limit != 0){
if (result.length > limit) { return result;}
}
if (node.leaf) { result.push.apply(result, node.children); }
else { nodesToSearch.push.apply(nodesToSearch, node.children); }
node = nodesToSearch.pop();
}
return result;
};`
Here is my latest modification, it works as expect:
credit to @mourner mourner to remind me must limit size at _all() function.
This is very important, without limit _all(), you will run into a leak,
You limit 20, but because of the leak, you could get 2000 in size, horrible leaking.
Now I fix the leaking.
`//modification by add limit result size
RBush.prototype.search = function search (bbox, limit) {
var node = this.data;
var result = [];
if (!intersects(bbox, node)) { return result; }
var toBBox = this.toBBox;
var nodesToSearch = [];
while (node) {
for (var i = 0; i < node.children.length; i++) {
var child = node.children[i];
var childBBox = node.leaf ? toBBox(child) : child;
if (intersects(bbox, childBBox)) {
if (node.leaf) {
//modification by add limit result size
// leaf means lowest level (feature element itself), 'child' in here means leaf, element iteself.
console.log('rbush -----1-----> result.length ', result.length, child, limit)
if ((result.length) > limit) { return result;}
result.push(child);
} else if (contains(bbox, childBBox)) {
//modification by add limit result size
// secondary lowest level, 'child' in here means a smallest branch with immediate leaf only
// we need to pass limit via _all()
console.log('rbush -----2-----> result.length ', result.length, child, child.children.length, limit)
this._all(child, result, limit);
} else {
//modification by add limit result size
// 'child' in here means high level big branch, with multiple mix of level 1,2,3
// we do not limit high level branch node, only limit lowest level leaf and lowest branch with immediate leaf _all()
console.log('rbush -----3-----> result.length ', result.length, child, limit)
nodesToSearch.push(child);
}
}
}
node = nodesToSearch.pop();
}
return result;
};`
also _all() function
`
//modification by add limit result size
RBush.prototype._all = function _all (node, result, limit) {
var nodesToSearch = [];
while (node) {
if (node.leaf) {
//modification by add limit result size
if (limit != 0){
// leaf means relatively lowest level ( node.children means to real lowest leaf )
console.log('rbush ----- node _all() -----> result.length ', result.length, node.children, limit)
if (((result.length) + (node.children.length))> limit) { return result;}
} else {
// limit = 0 means, no limit, nothing to do
}
result.push.apply(result, node.children);
}else {
//modification by add limit result size
// we do not limit high level branch node, only limit lowest level leaf and lowest branch with immediate leaf
nodesToSearch.push.apply(nodesToSearch, node.children);
}
node = nodesToSearch.pop();
}
return result;
};
`
not sure all() was use for? but anyway, just be safe,
` RBush.prototype.all = function all () {
//modification by add limit result size
//return this._all(this.data, []);
return this._all(this.data, [], 0);
};`
Now the only problem is geographic distribution is not balanced,
As you can see, I limit 20 of total 151891,
Ideally, the 20 point should geographically even distribute cross whole map view window,
reality is it centralize in right side corner, ( see those cluster of yellow tiny circle on pic)
How to geographically even the distribution while limit the size?