Ejemplo n.º 1
0
def get_place(id: str,
              request: Request,
              lang: str = None,
              type=None,
              verbosity=DEFAULT_VERBOSITY) -> Place:
    """Main handler that returns the requested place"""
    es = get_elasticsearch()
    verbosity = validate_verbosity(verbosity)
    lang = validate_lang(lang)

    # Handle place from "pages jaunes"
    if id.startswith(pj_source.PLACE_ID_PREFIX):
        pj_place = pj_source.get_place(id)
        log_place_request(pj_place, request.headers)
        return pj_place.load_place(lang, verbosity)

    #  Otherwise handle places from the ES db
    es_place = fetch_es_place(id, es, INDICES, type)

    places = {
        "admin": Admin,
        "street": Street,
        "addr": Address,
        "poi": POI,
    }
    loader = places.get(es_place.get("_type"))

    if loader is None:
        prometheus.exception("FoundPlaceWithWrongType")
        raise Exception("Place with id '{}' has a wrong type: '{}'".format(
            id, es_place[0].get("_type")))

    place = loader(es_place["_source"])
    log_place_request(place, request.headers)
    return place.load_place(lang, verbosity)
Ejemplo n.º 2
0
def get_status():
    """Returns the status of the elastic cluster
    """
    es = get_elasticsearch()
    try:
        cluster_health = es.cluster.health()
    except ConnectionError as err:
        logging.getLogger(__name__).error("Failed to connect to ES: %s", err)
        cluster_health = {}
        es_reachable = False
    else:
        es_reachable = True

    es_cluster_health = cluster_health.get("status") in ES_RUNNING_STATUS

    # the 'ready' is used as the readyness probe.
    # for the moment idunn is ready if ES is reachable
    ready = es_cluster_health
    return {
        "es": {
            "reachable": es_reachable,
            "running": es_cluster_health
        },
        "ready": ready
    }
Ejemplo n.º 3
0
def get_poi(id: str, lang: str = None) -> POI:
    """Handler that returns points-of-interest"""
    es = get_elasticsearch()
    if not lang:
        lang = settings["DEFAULT_LANGUAGE"]
    lang = lang.lower()

    es_poi = fetch_es_poi(id, es)
    return POI(es_poi).load_place(lang, verbosity=DEFAULT_VERBOSITY)
Ejemplo n.º 4
0
def fetch_es_pois(filters: [MimirPoiFilter], bbox, max_size) -> list:
    es = get_elasticsearch()
    left, bot, right, top = bbox[0], bbox[1], bbox[2], bbox[3]

    should_terms = []
    for f in filters:
        terms = f.get_terms_filters()
        if terms == []:
            should_terms.append({"match_all": {}})
        else:
            should_terms.append({
                "bool": {
                    "must": [{
                        "term": {
                            "poi_type.name": term
                        }
                    } for term in terms]
                }
            })

    # pylint: disable = unexpected-keyword-arg
    bbox_places = es.search(
        index=INDICES["poi"],
        body={
            "query": {
                "bool": {
                    "should": should_terms,
                    "minimum_should_match": 1,
                    "filter": {
                        "geo_bounding_box": {
                            "coord": {
                                "top_left": {
                                    "lat": top,
                                    "lon": left
                                },
                                "bottom_right": {
                                    "lat": bot,
                                    "lon": right
                                },
                            }
                        }
                    },
                }
            },
            "sort": {
                "weight": "desc"
            },
        },
        size=max_size,
        timeout="3s",
        ignore_unavailable=True,
    )

    bbox_places = bbox_places.get("hits", {}).get("hits", [])
    return bbox_places
Ejemplo n.º 5
0
def get_places_bbox(
    bbox: Any,
    category: Optional[List[str]] = Query(None),
    raw_filter: Optional[List[str]] = Query(None),
    source: Optional[str] = Query(None),
    q: Optional[str] = Query(None),
    size: Optional[int] = Query(None),
    lang: Optional[str] = Query(None),
    verbosity: Optional[str] = Query(None),
):
    es = get_elasticsearch()
    raw_params = get_raw_params(bbox, category, raw_filter, source, q, size, lang, verbosity)
    try:
        params = PlacesQueryParam(**raw_params)
    except ValidationError as e:
        logger.info(f"Validation Error: {e.json()}")
        raise HTTPException(status_code=400, detail=e.errors())

    source = params.source
    if source is None:
        if params.q:
            # PJ is currently the only source that accepts arbitrary queries
            source = SOURCE_PAGESJAUNES
        elif (
            params.category
            and all(c.get("pj_filters") for c in params.category)
            and pj_source.bbox_is_covered(params.bbox)
        ):
            source = SOURCE_PAGESJAUNES
        else:
            source = SOURCE_OSM

    if source == SOURCE_PAGESJAUNES:
        all_categories = [pj_category for c in params.category for pj_category in c["pj_filters"]]
        places_list = pj_source.get_places_bbox(
            all_categories, params.bbox, size=params.size, query=params.q
        )
    else:
        # Default source (OSM)
        if params.raw_filter:
            raw_filters = params.raw_filter
        else:
            raw_filters = [f for c in params.category for f in c["raw_filters"]]

        bbox_places = fetch_bbox_places(
            es, INDICES, raw_filters=raw_filters, bbox=params.bbox, max_size=params.size
        )
        places_list = [POI(p["_source"]) for p in bbox_places]

    return {
        "places": [p.load_place(params.lang, params.verbosity) for p in places_list],
        "source": source,
    }
Ejemplo n.º 6
0
Archivo: utils.py Proyecto: Qwant/idunn
def place_from_id(id: str, type=None, follow_redirect=False):
    """
    :param id: place id
    :param type: Optional type to restrict query in Elasticsearch
    :param follow_redirect: if false, RedirectToPlaceId may be raised
    :return: Place
    """
    try:
        namespace, suffix = id.split(":", 1)
    except ValueError as exc:
        raise InvalidPlaceId(id) from exc

    # Handle place from "pages jaunes"
    if namespace == pj_source.PLACE_ID_NAMESPACE:
        return pj_source.get_place(id)

    # Simple latlon place id
    if namespace == Latlon.PLACE_ID_NAMESPACE:
        return Latlon.from_id(id)

    # Otherwise handle places from the ES db
    es = get_elasticsearch()
    try:
        es_place = fetch_es_place(id, es, type)
    except PlaceNotFound as exc:
        if namespace == "addr":
            # A Latlon place can be used as a substitute for a "addr:<lon>;<lat>" id
            # that is not present in the database anymore
            try:
                lon, lat = suffix.split(":", 1)[0].split(";")
                latlon_id = Latlon(lat=lat, lon=lon).get_id()
            except ValueError:
                pass
            else:
                if not follow_redirect:
                    raise RedirectToPlaceId(latlon_id) from exc
                return place_from_id(latlon_id, follow_redirect=False)
        raise

    places = {
        "admin": Admin,
        "street": Street,
        "addr": Address,
        "poi": POI,
    }
    loader = places.get(es_place.get("_type"))

    if loader is None:
        prometheus.exception("FoundPlaceWithWrongType")
        raise Exception(
            f"Place with id '{id}' has a wrong type: '{es_place[0].get('_type')}'"
        )
    return loader(es_place["_source"])
Ejemplo n.º 7
0
def get_place_latlon(lat: float,
                     lon: float,
                     lang: str = None,
                     verbosity=DEFAULT_VERBOSITY) -> Place:
    es = get_elasticsearch()
    verbosity = validate_verbosity(verbosity)
    lang = validate_lang(lang)
    try:
        closest_place = get_closest_place(lat, lon, es)
    except HTTPException:
        closest_place = None
    place = Latlon(lat, lon, closest_address=closest_place)
    return place.load_place(lang, verbosity)
Ejemplo n.º 8
0
def closest_address(lat: float, lon: float, lang=None, verbosity=DEFAULT_VERBOSITY) -> Address:
    if verbosity not in ALL_VERBOSITY_LEVELS:
        raise HTTPException(
            status_code=400,
            detail=f"Unknown verbosity '{verbosity}'. Accepted values are {ALL_VERBOSITY_LEVELS}",
        )
    es = get_elasticsearch()

    if not lang:
        lang = settings["DEFAULT_LANGUAGE"]
    lang = lang.lower()

    place = get_closest_place(lat, lon, es)
    return place.load_place(lang, verbosity)
Ejemplo n.º 9
0
def closest_address(
    lat: confloat(ge=-90, le=90),
    lon: confloat(ge=-180, le=180),
    lang=None,
    verbosity: Verbosity = Verbosity.default(),
) -> Place:
    """Find the closest address to a point."""

    es = get_elasticsearch()

    if not lang:
        lang = settings["DEFAULT_LANGUAGE"]
    lang = lang.lower()

    place = get_closest_place(lat, lon, es)
    return place.load_place(lang, verbosity)
Ejemplo n.º 10
0
def get_place_latlon(
    lat: confloat(ge=-90, le=90),
    lon: confloat(ge=-180, le=180),
    lang: str = None,
    verbosity: Verbosity = Verbosity.default(),
) -> Place:
    """Find the closest place to a point."""

    es = get_elasticsearch()
    lang = validate_lang(lang)
    try:
        closest_place = get_closest_place(lat, lon, es)
    except HTTPException:
        closest_place = None
    place = Latlon(lat, lon, closest_address=closest_place)
    return place.load_place(lang, verbosity)
Ejemplo n.º 11
0
def get_closest_place(lat: float, lon: float, es=None):
    if es is None:
        es = get_elasticsearch()
    es_addr = fetch_closest(lat, lon, es=es, max_distance=MAX_DISTANCE_IN_METERS)

    places = {
        "addr": Address,
        "street": Street,
    }
    loader = places.get(es_addr.get("_type"))

    if loader is None:
        logger.warning("Found a place with the wrong type")
        prometheus.exception("FoundPlaceWithWrongType")
        raise HTTPException(
            status_code=404,
            detail=f"Closest address to '{lat}:{lon}' has a wrong type: '{es_addr.get('_type')}'",
        )

    return loader(es_addr["_source"])