示例#1
0
def map_data():
    """
    Given a specific cuisine and a latitude, longitude, and diagonal bound
    in meters, return a dictionary mapping the ID of the restaurant to a
    pair of (longitude, latitude).
    
    Arguments:
    cuisine - A string representing the given restaurant type, e.g. 'pizza'.
    latitude - A float representing the latitude of the center of the map.
    longitude - A float representing the longitude of the center of the map.
    diag - The distance, in meters, from the northwest corner of the map to the
           southeast corner of the map.
    """
    cuisine = request.args.get('cuisine') # Required
    latitude = request.args.get('lat') # Required
    longitude = request.args.get('lng') # Required
    diag = request.args.get('diag') # Required

    response = {}

    r = get_redis_client()

    ################################## TODO ###################################
    # https://redis.io/commands/georadius
    #   GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
    
    response.update(r.georadius('geo:'+cuisine, longitude, latitude, float(diag)/2, unit='m', withcoord=True))

    ############################### END TODO ###################################

    return json.dumps(response)
示例#2
0
def cuisine_ratings():
    """
    Return JSON mapping each rating value (1-5) to the number of restaurants that
    have been rated with this rating.
    """
    cuisine = request.args.get('cuisine')  # Required

    response = {}
    r = get_redis_client()

    pipe = r.pipeline(transaction=False)  # Batch together multiple requests

    ################################## TODO ####################################
    # https://redis.io/commands/zcount
    #  ZCOUNT key min max

    # Set up the pipeline

    for i in range(1, 6):
        pipe.zcount('ratings:' + cuisine, i, i)

    results = pipe.execute()

    # Store the results into the response dictionary

    i = 1
    for item in results:
        response[i] = item
        i += 1

    ############################### END TODO ###################################

    return json.dumps(response, sort_keys=True)
示例#3
0
def rating():
    """
    Get or set the restaurant's rating.  If a rating is provided in input, set
    the rating for each cuisine sorted set and return it.  Otherwise, look up
    the rating and return it as a string.
    """
    id = request.args.get('id')  # Required
    rating = request.args.get('rating')  # Optional

    r = get_redis_client()

    # Fetch the cuisine for the restaurant
    data = get_restaurant_data(r, id, 'tag:cuisine')
    if 'tag:cuisine' not in data:
        return "0"
    cuisine = data['tag:cuisine']

    # Set the rating if provided
    if rating:
        set_rating(r, cuisine, id, rating)

    # Always look up rating at the end to make sure it's set
    rating = get_rating(r, cuisine, id)
    if rating:
        return str(rating)
    else:
        return "0"
示例#4
0
def restaurant_list():
    """
    Return JSON mapping restaurant identifiers to their public-facing names.
    To filter the set of restaurants, a cuisine type is provided, as well as
    the map's diagonal distance.
    
    Arguments:
    cuisine - A string representing the given restaurant type, e.g. 'pizza'.
    latitude - A float representing the latitude of the center of the map.
    longitude - A float representing the longitude of the center of the map.
    diag - The distance, in meters, from the northwest corner of the map to the
           southeast corner of the map.
    """
    cuisine = request.args.get('cuisine') # Required
    longitude = request.args.get('lng') # Required
    latitude = request.args.get('lat') # Required
    diag = request.args.get('diag') # Required

    response = {}

    r = get_redis_client()

    # Use this LUA template and fill in the function calls to return id, name
    # pairs for entries that are geographically close.
    lua_script_template = Template('''
local results = {}
for i, id in ipairs($redis_function_call1) do
  local name = $redis_function_call2
  table.insert(results, id)
  table.insert(results, name)
end
return results''')

    ################################## TODO ####################################
    # https://redis.io/commands/eval
    #  EVAL script numkeys key [key ...] arg [arg ...]
    #
    # The restaurant's name is stored in the property 'tag:name'
    
    lua_script = lua_script_template.substitute(
        redis_function_call1="redis.call('GEORADIUS', KEYS[1], ARGV[1], ARGV[2], ARGV[3], 'm')",
        redis_function_call2="redis.call('HGET', id, 'tag:name')"
        )

    # EVAL call to Redis goes here and returns a list
    members = r.eval(lua_script, 1, 'geo:'+cuisine, longitude, latitude, float(diag)/2)

    ############################### END TODO ###################################

    it = iter(members)
    for item in it:
        name = next(it)
        # Some restaurants may not have a name - handle this gracefully
        if name is None:
            name = "Unknown "+cuisine
        response[item] = name
        
    return json.dumps(response, sort_keys=True)
示例#5
0
def restaurant_detail():
    id = request.args.get('id') # Required
    field = request.args.get('field') # Optional

    r = get_redis_client()

    response = get_restaurant_data(r, id, field)

    return json.dumps(response, sort_keys=True)
def import_data(filename):
    """Parse the restaurant information from the given OSM XML data file and store in Redis"""
    print(filename)
    global progress
    global stop

    r = get_redis_client()
    r.flushall()

    total_size = os.path.getsize(filename)
    print(total_size)
    with open(filename, 'r') as f:
        context = ET.iterparse(f, events=('start', 'end'))
        context = iter(context)

        event, root = next(context)

        cuisine_item = False  # Whether the current item has a tag with key 'cuisine'
        node_item = False  # Whether the current item has a 'node' tag
        for event, item in context:
            if stop:
                break

            # Process all nodes and their children
            progress = float(f.tell()) / total_size

            if event == 'start':
                if item.tag == 'node':
                    node_item = True  # Currently parsing a node
                continue
            elif not node_item:
                root.clear()  # GC
                continue

            if item.tag == 'tag' and item.attrib['k'] == 'cuisine':
                cuisine_item = True
            if item.tag == 'node':
                if cuisine_item:
                    cuisine_item = False
                    process_node(r, item)
                root.clear()
                node_item = False

    if not stop:
        progress = 1

    stop = False
示例#7
0
def restaurant_frequencies():
    """
    Return JSON mapping cuisine to the number of restaurants serving that
    cuisine.  The dictionary should contain the top cuisines in order by
    frequency.
    """
    response = OrderedDict() # Dictionary that maintains order added

    r = get_redis_client()

    ################################## TODO ####################################
    # https://redis.io/commands/zcount
    #  ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]

    response.update(r.zrevrangebyscore('cuisine_rankings', '+inf', '-inf', withscores=True))

    ############################### END TODO ###################################

    return json.dumps(response)
示例#8
0
def clear_ratings():
    """
    Clear all ratings, leaving other data intact.
    """

    r = get_redis_client()

    ################################## TODO ####################################
    # https://redis.io/commands/scan
    #  SCAN cursor [MATCH pattern] [COUNT count]
    # https://redis.io/commands/del
    #  DEL key [key ...]

    for key in r.scan_iter('ratings:*'):
        r.delete(key)

    ############################### END TODO ###################################

    return json.dumps({
        "result": "ok",
    })