Ejemplo n.º 1
0
    void S2SimpleCursor::seek(const BSONObj& query, const vector<GeoQuery>& regions) {
        _nscanned = 0;
        _matchTested = 0;
        _geoTested = 0;
        _fields = regions;
        _seen = unordered_set<DiskLoc, DiskLoc::Hasher>();

        BSONObjBuilder geoFieldsToNuke;
        for (size_t i = 0; i < _fields.size(); ++i) {
            geoFieldsToNuke.append(_fields[i].getField(), "");
        }
        // false means we want to filter OUT geoFieldsToNuke, not filter to include only that.
        _filteredQuery = query.filterFieldsUndotted(geoFieldsToNuke.obj(), false);

        BSONObjBuilder specBuilder;
        BSONObjIterator i(_descriptor->keyPattern());
        while (i.more()) {
            BSONElement e = i.next();
            // Checked in AccessMethod already, so we know this spec has only numbers and 2dsphere
            if ( e.type() == String ) {
                specBuilder.append( e.fieldName(), 1 );
            }
            else {
                specBuilder.append( e.fieldName(), e.numberInt() );
            }
        }
        BSONObj spec = specBuilder.obj();

        BSONObj frsObj;

        BSONObjBuilder frsObjBuilder;
        frsObjBuilder.appendElements(_filteredQuery);

        S2RegionCoverer coverer;

        for (size_t i = 0; i < _fields.size(); ++i) {
            vector<S2CellId> cover;
            double area = _fields[i].getRegion().GetRectBound().Area();
            S2SearchUtil::setCoverLimitsBasedOnArea(area, &coverer, _params.coarsestIndexedLevel);
            coverer.GetCovering(_fields[i].getRegion(), &cover);
            uassert(16759, "No cover ARGH?!", cover.size() > 0);
            _cellsInCover = cover.size();
            BSONObj fieldRange = S2SearchUtil::coverAsBSON(cover, _fields[i].getField(),
                    _params.coarsestIndexedLevel);
            frsObjBuilder.appendElements(fieldRange);
        }

        frsObj = frsObjBuilder.obj();

        FieldRangeSet frs(_descriptor->parentNS().c_str(), frsObj, false, false);
        shared_ptr<FieldRangeVector> frv(new FieldRangeVector(frs, spec, 1));
        _btreeCursor.reset(BtreeCursor::make(nsdetails(_descriptor->parentNS()),
                                             _descriptor->getOnDisk(), frv, 0, 1));
        next();
    }
Ejemplo n.º 2
0
    BSONObj S2NearCursor::makeFRSObject() {
        BSONObjBuilder frsObjBuilder;
        frsObjBuilder.appendElements(_filteredQuery);

        S2RegionCoverer coverer;
        // Step 1: Make the BSON'd covering for our search annulus.
        BSONObj inExpr;
        // Caps are inclusive and inverting a cap includes the border.  This means that our
        // initial _innerRadius of 0 is OK -- we'll still find a point that is exactly at
        // the start of our search.
        S2Cap innerCap = S2Cap::FromAxisAngle(_nearQuery.centroid,
                                              S1Angle::Radians(_innerRadius / _params.radius));
        S2Cap invInnerCap = innerCap.Complement();
        S2Cap outerCap = S2Cap::FromAxisAngle(_nearQuery.centroid,
                                              S1Angle::Radians(_outerRadius / _params.radius));
        vector<S2Region*> regions;
        regions.push_back(&invInnerCap);
        regions.push_back(&outerCap);
        S2RegionIntersection shell(&regions);
        vector<S2CellId> cover;
        double area = outerCap.area() - innerCap.area();
        S2SearchUtil::setCoverLimitsBasedOnArea(area, &coverer, _params.coarsestIndexedLevel);
        coverer.GetCovering(shell, &cover);
        LOG(2) << "annulus cover size is " << cover.size()
               << ", params (" << coverer.min_level() << ", " << coverer.max_level() << ")"
               << endl;
        inExpr = S2SearchUtil::coverAsBSON(cover, _nearQuery.field,
                                           _params.coarsestIndexedLevel);
        // Shell takes ownership of the regions we push in, but they're local variables and
        // deleting them would be bad.
        shell.Release(NULL);
        frsObjBuilder.appendElements(inExpr);

        _params.configureCoverer(&coverer);
        // Cover the indexed geo components of the query.
        for (size_t i = 0; i < _indexedGeoFields.size(); ++i) {
            vector<S2CellId> cover;
            coverer.GetCovering(_indexedGeoFields[i].getRegion(), &cover);
            uassert(16682, "Couldn't generate index keys for geo field "
                       + _indexedGeoFields[i].getField(),
                    cover.size() > 0);
            BSONObj fieldRange = S2SearchUtil::coverAsBSON(cover, _indexedGeoFields[i].getField(),
                _params.coarsestIndexedLevel);
            frsObjBuilder.appendElements(fieldRange);
        }

        return frsObjBuilder.obj();
    }
std::vector<S2CellId> ExpressionMapping::get2dsphereCovering(const S2Region& region) {
    auto minLevel = internalQueryS2GeoCoarsestLevel.load();
    auto maxLevel = internalQueryS2GeoFinestLevel.load();

    uassert(28739, "Geo coarsest level must be in range [0,30]", 0 <= minLevel && minLevel <= 30);
    uassert(28740, "Geo finest level must be in range [0,30]", 0 <= maxLevel && maxLevel <= 30);
    uassert(28741, "Geo coarsest level must be less than or equal to finest", minLevel <= maxLevel);

    S2RegionCoverer coverer;
    coverer.set_min_level(minLevel);
    coverer.set_max_level(maxLevel);
    coverer.set_max_cells(internalQueryS2GeoMaxCells.load());

    std::vector<S2CellId> cover;
    coverer.GetCovering(region, &cover);
    return cover;
}
Ejemplo n.º 4
0
    // Make the FieldRangeSet of keys we look for.  Uses coverAsBSON to go from
    // a region to a covering to a set of keys for that covering.
    // Returns false if the FRS object would be empty.
    bool S2Cursor::makeFRSObject(BSONObj *out) {
        BSONObjBuilder frsObjBuilder;
        frsObjBuilder.appendElements(_filteredQuery);

        S2RegionCoverer coverer;

        for (size_t i = 0; i < _fields.size(); ++i) {
            vector<S2CellId> cover;
            double area = _fields[i].getRegion().GetRectBound().Area();
            S2SearchUtil::setCoverLimitsBasedOnArea(area, &coverer, _params.coarsestIndexedLevel);
            coverer.GetCovering(_fields[i].getRegion(), &cover);
            if (0 == cover.size()) { return false; }
            _cellsInCover = cover.size();
            BSONObj fieldRange = S2SearchUtil::coverAsBSON(cover, _fields[i].getField(),
                _params.coarsestIndexedLevel);
            frsObjBuilder.appendElements(fieldRange);
        }

        *out = frsObjBuilder.obj();
        return true;
    }
Ejemplo n.º 5
0
    // TODO: what should we really pass in for indexInfoObj?
    void ExpressionMapping::cover2dsphere(const S2Region& region,
                                          const BSONObj& indexInfoObj,
                                          OrderedIntervalList* oilOut) {

        int coarsestIndexedLevel;
        BSONElement ce = indexInfoObj["coarsestIndexedLevel"];
        if (ce.isNumber()) {
            coarsestIndexedLevel = ce.numberInt();
        }
        else {
            coarsestIndexedLevel =
                S2::kAvgEdge.GetClosestLevel(100 * 1000.0 / kRadiusOfEarthInMeters);
        }

        // The min level of our covering is the level whose cells are the closest match to the
        // *area* of the region (or the max indexed level, whichever is smaller) The max level
        // is 4 sizes larger.
        double edgeLen = sqrt(region.GetRectBound().Area());
        S2RegionCoverer coverer;
        coverer.set_min_level(min(coarsestIndexedLevel,
                                  2 + S2::kAvgEdge.GetClosestLevel(edgeLen)));
        coverer.set_max_level(4 + coverer.min_level());

        std::vector<S2CellId> cover;
        coverer.GetCovering(region, &cover);

        // Look at the cells we cover and all cells that are within our covering and finer.
        // Anything with our cover as a strict prefix is contained within the cover and should
        // be intersection tested.
        bool considerCoarser = false;
        std::set<std::string> intervalSet;
        for (size_t i = 0; i < cover.size(); ++i) {
            intervalSet.insert(cover[i].toString());
            // If any of our covers could be covered by something in the index, we have
            // to look at things coarser.
            if (cover[i].level() > coarsestIndexedLevel) {
                considerCoarser = true;
            }
        }

        std::set<std::string> exactSet;
        if (considerCoarser) {
            // Look at the cells that cover us.  We want to look at every cell that contains the
            // covering we would index on if we were to insert the query geometry.  We generate
            // the would-index-with-this-covering and find all the cells strictly containing the
            // cells in that set, until we hit the coarsest indexed cell.  We use equality, not
            // a prefix match.  Why not prefix?  Because we've already looked at everything
            // finer or as fine as our initial covering.
            //
            // Say we have a fine point with cell id 212121, we go up one, get 21212, we don't
            // want to look at cells 21212[not-1] because we know they're not going to intersect
            // with 212121, but entries inserted with cell value 21212 (no trailing digits) may.
            // And we've already looked at points with the cell id 211111 from the regex search
            // created above, so we only want things where the value of the last digit is not
            // stored (and therefore could be 1).
            for (size_t i = 0; i < cover.size(); ++i) {
                for (S2CellId id = cover[i].parent(); id.level() >= coarsestIndexedLevel;
                        id = id.parent()) {
                    exactSet.insert(id.toString());
                }
            }
        }

        // We turned the cell IDs into strings which define point intervals or prefixes of
        // strings we want to look for.
        std::set<std::string>::iterator exactIt = exactSet.begin();
        std::set<std::string>::iterator intervalIt = intervalSet.begin();
        while (exactSet.end() != exactIt && intervalSet.end() != intervalIt) {
            const std::string& exact = *exactIt;
            const std::string& ival = *intervalIt;
            if (exact < ival) {
                // add exact
                oilOut->intervals.push_back(IndexBoundsBuilder::makePointInterval(exact));
                exactIt++;
            }
            else {
                std::string end = ival;
                end[end.size() - 1]++;
                oilOut->intervals.push_back(
                    IndexBoundsBuilder::makeRangeInterval(ival, end, true, false));
                intervalIt++;
            }
        }

        if (exactSet.end() != exactIt) {
            verify(intervalSet.end() == intervalIt);
            do {
                oilOut->intervals.push_back(IndexBoundsBuilder::makePointInterval(*exactIt));
                exactIt++;
            } while (exactSet.end() != exactIt);
        }
        else if (intervalSet.end() != intervalIt) {
            verify(exactSet.end() == exactIt);
            do {
                const std::string& ival = *intervalIt;
                std::string end = ival;
                end[end.size() - 1]++;
                oilOut->intervals.push_back(
                    IndexBoundsBuilder::makeRangeInterval(ival, end, true, false));
                intervalIt++;
            } while (intervalSet.end() != intervalIt);
        }

        // Make sure that our intervals don't overlap each other and are ordered correctly.
        // This perhaps should only be done in debug mode.
        if (!oilOut->isValidFor(1)) {
            cout << "check your assumptions! OIL = " << oilOut->toString() << std::endl;
            verify(0);
        }
    }
Ejemplo n.º 6
0
static void
s2cover_request_cb(struct evhttp_request *req, void *arg)
{
  struct evkeyvalq  args;

  struct evbuffer *inputBuffer = evhttp_request_get_input_buffer (req);
  size_t record_len = evbuffer_get_length(inputBuffer);
  char *postData = NULL;
  const char *path = "/?";
  if (record_len > 0) { 
    postData = (char *)malloc(strlen(path) + record_len + 10);
    postData[0] = '/';
    postData[1] = '?';
    evbuffer_pullup(inputBuffer, -1);                                                                                                                                                     
    evbuffer_copyout(inputBuffer, (char *)postData + strlen(path), record_len);
    postData[strlen(path) + record_len] = '\0';
    printf("trying to parse: %s\n", (const char *)postData);
    evhttp_parse_query((const char *)postData, &args);
    char* points = (char *)evhttp_find_header(&args, "points");
    cout << points << endl;
  } else {
    const char *uri = evhttp_request_get_uri(req);
    evhttp_parse_query(uri, &args);
  }

  char* callback = (char *)evhttp_find_header(&args, "callback");

  char* points = (char *)evhttp_find_header(&args, "points");
  std::vector<S2CellId> cellids_vector;
  if (points != NULL) {
    printf(points);
    scoped_ptr<S2PolygonBuilder> builder(new S2PolygonBuilder(S2PolygonBuilderOptions::DIRECTED_XOR()));
    
    std::vector<std::string> points_vector = split(string(points), ',');
    std::vector<S2Point> s2points_vector;

    for (int i = 0; i < points_vector.size(); i += 2) {
      char *endptr;
      s2points_vector.push_back(S2LatLng::FromDegrees(
        strtod(points_vector[i].c_str(), &endptr),
        strtod(points_vector[i+1].c_str(), &endptr)
      ).ToPoint());
    }

    if (s2points_vector.size() == 1) {
      char* min_level = (char *)evhttp_find_header(&args, "min_level");
      if (min_level == NULL) {
        min_level = (char *)evhttp_find_header(&args, "max_level");
      }
      if (min_level == NULL) {
        min_level = "14";
      }

      int min_level_int = atoi(min_level);
      if (min_level_int > S2::kMaxCellLevel) {
        min_level_int = S2::kMaxCellLevel;
      }
      if (min_level_int < 0) {
        min_level_int = 0;
      }

      cellids_vector.push_back(S2CellId::FromPoint(s2points_vector[0]).parent(min_level_int));
    } else {
      for (int i = 0; i < s2points_vector.size(); i++) {
        builder->AddEdge(
          s2points_vector[i],
          s2points_vector[(i + 1) % s2points_vector.size()]);
      }

      S2Polygon polygon;
      typedef vector<pair<S2Point, S2Point> > EdgeList;
      EdgeList edgeList;
      builder->AssemblePolygon(&polygon, &edgeList);

      S2RegionCoverer coverer;

      char* min_level = (char *)evhttp_find_header(&args, "min_level");
      if (min_level) {
	int min_level_int = atoi(min_level);
	if (min_level_int > S2::kMaxCellLevel) {
	  min_level_int = S2::kMaxCellLevel;
        }
        if (min_level_int < 0) {
          min_level_int = 0;
        }
        coverer.set_min_level(min_level_int);
      }

      char* max_level = (char *)evhttp_find_header(&args, "max_level");
      if (max_level) {
	int max_level_int = atoi(max_level);
	if (max_level_int > S2::kMaxCellLevel) {
	  max_level_int = S2::kMaxCellLevel;
        }
        if (max_level_int < 0) {
          max_level_int = 0;
        }
        coverer.set_max_level(max_level_int);
      }

      char* level_mod = (char *)evhttp_find_header(&args, "level_mod");
      if (level_mod) {
        coverer.set_level_mod(atoi(level_mod));
      }

      char* max_cells = (char *)evhttp_find_header(&args, "max_cells");
      if (max_cells) {
        coverer.set_max_cells(atoi(max_cells));
      }

      coverer.GetCovering(polygon, &cellids_vector); 
    }
  }

  printf("\n");

	evhttp_add_header(evhttp_request_get_output_headers(req),
		    "Content-Type", "application/json");
	struct evbuffer *evb = NULL;
	evb = evbuffer_new();
  char* json = s2CellIdsToJson(callback, cellids_vector);
  evbuffer_add_printf(evb, "%s", json);
	evhttp_send_reply(req, 200, "OK", evb);
 
  free(json);

  if (postData)
    free(postData);

  if (evb)
    evbuffer_free(evb);
}