mirror of https://gitee.com/bigwinds/arangodb
optimizations for geo index
This commit is contained in:
parent
9e7a98332d
commit
16f16b768d
|
@ -654,10 +654,13 @@ void GeoMkDetail(GeoIx* gix, GeoDetailedPoint* gd, GeoCoordinate* c) {
|
|||
gd->gc = c;
|
||||
/* The GeoString computation takes about 0.17 microseconds */
|
||||
gd->gs = GeoMkHilbert(c);
|
||||
double const lat = c->latitude * M_PI / 180.0;
|
||||
double const lon = c->longitude * M_PI / 180.0;
|
||||
double const latCos = cos(lat);
|
||||
/* This part takes about 0.32 microseconds */
|
||||
gd->z = sin(c->latitude * M_PI / 180.0);
|
||||
gd->x = cos(c->latitude * M_PI / 180.0) * cos(c->longitude * M_PI / 180.0);
|
||||
gd->y = cos(c->latitude * M_PI / 180.0) * sin(c->longitude * M_PI / 180.0);
|
||||
gd->z = sin(lat);
|
||||
gd->x = latCos * cos(lon);
|
||||
gd->y = latCos * sin(lon);
|
||||
/* And this bit takes about 0.45 microseconds */
|
||||
for (int i = 0; i < GeoIndexFIXEDPOINTS; i++) {
|
||||
double xx1 = (gix->fixed.x)[i];
|
||||
|
@ -927,7 +930,7 @@ int GeoResultsGrow(GeoResults* gr) {
|
|||
/* distances that could be calculated by a separate */
|
||||
/* call to GeoIndex_distance because of rounding errors*/
|
||||
/* =================================================== */
|
||||
GeoCoordinates* GeoAnswers(GeoIx* gix, GeoResults* gr) {
|
||||
GeoCoordinates* GeoAnswers(GeoIx* gix, GeoResults* gr, bool withDistances) {
|
||||
GeoCoordinates* ans;
|
||||
GeoCoordinate* gc;
|
||||
int i, j;
|
||||
|
@ -967,11 +970,14 @@ GeoCoordinates* GeoAnswers(GeoIx* gix, GeoResults* gr) {
|
|||
ans->coordinates[j].latitude = (gix->gc)[slot].latitude;
|
||||
ans->coordinates[j].longitude = (gix->gc)[slot].longitude;
|
||||
ans->coordinates[j].data = (gix->gc)[slot].data;
|
||||
mole = sqrt(gr->snmd[i]);
|
||||
if (mole > 2.0) mole = 2.0; /* make sure arcsin succeeds! */
|
||||
gr->snmd[j] = 2.0 * EARTHRADIAN * asin(mole / 2.0);
|
||||
if (withDistances) {
|
||||
mole = sqrt(gr->snmd[i]);
|
||||
if (mole > 2.0) mole = 2.0; /* make sure arcsin succeeds! */
|
||||
gr->snmd[j] = 2.0 * EARTHRADIAN * asin(mole / 2.0);
|
||||
}
|
||||
j++;
|
||||
}
|
||||
// note that these are uncalculated if withDistances is false!
|
||||
ans->distances = gr->snmd;
|
||||
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, gr->slot);
|
||||
|
@ -1094,7 +1100,7 @@ GeoCoordinates* GeoIndex_PointsWithinRadius(GeoIdx* gi, GeoCoordinate* c,
|
|||
gk.potid[gk.stacksize++] = gp->RorPoints;
|
||||
}
|
||||
}
|
||||
answer = GeoAnswers(gix, gres);
|
||||
answer = GeoAnswers(gix, gres, true);
|
||||
return answer; /* note - this may be NULL */
|
||||
}
|
||||
/* =================================================== */
|
||||
|
@ -1159,7 +1165,7 @@ GeoCoordinates* GeoIndex_NearestCountPoints(GeoIdx* gi, GeoCoordinate* c,
|
|||
}
|
||||
}
|
||||
}
|
||||
answer = GeoAnswers(gix, gr);
|
||||
answer = GeoAnswers(gix, gr, true);
|
||||
return answer; /* note - this may be NULL */
|
||||
}
|
||||
/* =================================================== */
|
||||
|
@ -2060,7 +2066,7 @@ GeoCursor* GeoIndex_NewCursor(GeoIdx* gi, GeoCoordinate* c) {
|
|||
return (GeoCursor*)gcr;
|
||||
}
|
||||
|
||||
GeoCoordinates* GeoIndex_ReadCursor(GeoCursor* gc, int count) {
|
||||
GeoCoordinates* GeoIndex_ReadCursor(GeoCursor* gc, int count, bool withDistances) {
|
||||
int i, j, r;
|
||||
GeoCoordinate* ct;
|
||||
GeoResults* gr;
|
||||
|
@ -2137,7 +2143,7 @@ GeoCoordinates* GeoIndex_ReadCursor(GeoCursor* gc, int count) {
|
|||
}
|
||||
}
|
||||
}
|
||||
gcts = GeoAnswers(gcr->Ix, gr);
|
||||
gcts = GeoAnswers(gcr->Ix, gr, withDistances);
|
||||
return gcts;
|
||||
}
|
||||
|
||||
|
|
|
@ -101,7 +101,7 @@ GeoCoordinates* GeoIndex_PointsWithinRadius(GeoIdx* gi, GeoCoordinate* c,
|
|||
GeoCoordinates* GeoIndex_NearestCountPoints(GeoIdx* gi, GeoCoordinate* c,
|
||||
int count);
|
||||
GeoCursor* GeoIndex_NewCursor(GeoIdx* gi, GeoCoordinate* c);
|
||||
GeoCoordinates* GeoIndex_ReadCursor(GeoCursor* gc, int count);
|
||||
GeoCoordinates* GeoIndex_ReadCursor(GeoCursor* gc, int count, bool withDistances = true);
|
||||
void GeoIndex_CursorFree(GeoCursor* gc);
|
||||
void GeoIndex_CoordinatesFree(GeoCoordinates* clist);
|
||||
#ifdef TRI_GEO_DEBUG
|
||||
|
|
|
@ -127,31 +127,66 @@ void GeoIndexIterator::nextBabies(std::vector<IndexLookupResult>& result, size_t
|
|||
}
|
||||
|
||||
if (batchSize > 0) {
|
||||
auto coords = std::unique_ptr<GeoCoordinates>(::GeoIndex_ReadCursor(_cursor, batchSize));
|
||||
// only need to calculate distances for WITHIN queries, but not for NEAR queries
|
||||
bool const withDistances = !_near;
|
||||
auto coords = std::unique_ptr<GeoCoordinates>(::GeoIndex_ReadCursor(_cursor, batchSize, withDistances));
|
||||
|
||||
size_t const length = coords ? coords->length : 0;
|
||||
if (!length) {
|
||||
|
||||
if (length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// determine which documents to return...
|
||||
size_t numDocs = length;
|
||||
|
||||
if (!_near) {
|
||||
// WITHIN
|
||||
// only return those documents that are within the specified radius
|
||||
TRI_ASSERT(numDocs > 0);
|
||||
// scan backwards because documents with higher distances are more interesting
|
||||
// this can be improved to use a binary search if block size is increased in the future
|
||||
while ((_inclusive && coords->distances[numDocs - 1] > _radius) ||
|
||||
(!_inclusive && coords->distances[numDocs - 1] >= _radius)) {
|
||||
// document is outside the specified radius!
|
||||
--numDocs;
|
||||
if (numDocs == 0) {
|
||||
break;
|
||||
|
||||
if (numDocs <= 8) {
|
||||
// linear scan for the first document outside the specified radius
|
||||
// scan backwards because documents with higher distances are more interesting
|
||||
while ((_inclusive && coords->distances[numDocs - 1] > _radius) ||
|
||||
(!_inclusive && coords->distances[numDocs - 1] >= _radius)) {
|
||||
// document is outside the specified radius!
|
||||
--numDocs;
|
||||
if (numDocs == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// binary search for documents inside/outside the specified radius
|
||||
size_t l = 0;
|
||||
size_t r = numDocs - 1;
|
||||
|
||||
while (true) {
|
||||
// determine midpoint
|
||||
size_t m = l + ((r - l) / 2);
|
||||
if ((_inclusive && coords->distances[m] > _radius) ||
|
||||
(!_inclusive && coords->distances[m] >= _radius)) {
|
||||
// document is outside the specified radius!
|
||||
if (m == 0) {
|
||||
numDocs = 0;
|
||||
break;
|
||||
}
|
||||
r = m - 1;
|
||||
} else {
|
||||
// still inside the radius
|
||||
numDocs = m + 1;
|
||||
l = m + 1;
|
||||
}
|
||||
|
||||
if (r < l) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
result.reserve(numDocs);
|
||||
|
||||
for (size_t i = 0; i < numDocs; ++i) {
|
||||
result.emplace_back(IndexLookupResult(::GeoIndex::toRevision(coords->coordinates[i].data)));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue