docs: protected void batchNN(AbstractRStarTreeNode<?, ?> node, Map<DBID, KNNHeap> knnLists) {
      if(node.isLeaf()) {
        for(int i = 0; i < node.getNumEntries(); i++) {
          SpatialEntry p = node.getEntry(i);
          for(Entry<DBID, KNNHeap> ent : knnLists.entrySet()) {
            final DBID q = ent.getKey();
            final KNNHeap knns_q = ent.getValue();
            double knn_q_maxDist = knns_q.getKNNDistance();
  
            DBID pid = ((LeafEntry) p).getDBID();
            // FIXME: objects are NOT accessible by DBID in a plain R-tree
            // context!
            double dist_pq = distanceFunction.distance(relation.get(pid), relation.get(q));
            tree.statistics.countDistanceCalculation();
            if(dist_pq <= knn_q_maxDist) {
              knns_q.insert(dist_pq, pid);
            }
          }
        }
      }
      else {
        ModifiableDBIDs ids = DBIDUtil.newArray(knnLists.size());
        for(DBID id : knnLists.keySet()) {
          ids.add(id);
        }
        List<DoubleDistanceEntry> entries = getSortedEntries(node, ids);
        for(DoubleDistanceEntry distEntry : entries) {
          double minDist = distEntry.distance;
          for(Entry<DBID, KNNHeap> ent : knnLists.entrySet()) {
            final KNNHeap knns_q = ent.getValue();
            double knn_q_maxDist = knns_q.getKNNDistance();
  
            if(minDist <= knn_q_maxDist) {
              SpatialEntry entry = distEntry.entry;
              AbstractRStarTreeNode<?, ?> child = tree.getNode(((DirectoryEntry) entry).getPageID());
              batchNN(child, knnLists);
              break;
            }
          }
        }
      }
    }