滑动窗口

import re
import datetime

logline = '''183.60.212.153 - - [19/Feb/2013:10:23:29 +0800] \
"GET /o2o/media.html?menu=3 HTTP/1.1" 200 16691 "-" \
"Mozilla/5.0 (compatible; EasouSpider; +http://www.easou.com/search/spider.html)"'''

pattern = '''(?P<remote>[\d\.]{7,}) - - \[(?P<datetime>[^\[\]]+)\] "(?P<request>[^"]+)" (?P<status>\d+) (?P<size>\d+) "([^"]+)" "(?P<useragent>[^"]+)'''

regex = re.compile(pattern)


def extract(line):
    matcher = regex.match(line)
    if matcher:
        return {k: ops.get(k, lambda x: x)(v) for k, v in matcher.groupdict().items()}


ops = {
    'datetime': lambda timestr: datetime.datetime.strptime(timestr, '%d/%b/%Y:%H:%M:%S %z'),
    'status': int,
    'size': int,
    'request': lambda request: dict(zip(('method', 'url', 'protocol'), request.split()))
}

# for k , v in extract(logline).items():
# d[k] = ops[k].get(k, lambda x:x)(v)
# {k:ops[k].get(k, lambda x:x)(v) for k , v in matcher.groupdict().items() }


'''
滑动窗口:
    数据载入:
    对于项目来说,数据就是日志的一行行记录,载入数据就是文件IO的读取,将
    获取数据的方法封装成函数
'''

def load(path:str):
    '''
    装载日志文件
    逐行读取文件
    '''
    with open(path) as f:
        for line in f:
            field = extract(line)
            if field:
                yield field #yield 是真好使
            else:
                continue #记录完每一条就continue
    #就变成了生成器函数,调用返回的是生成器对象 然后就需要next迭代

'''
    时间窗口分析:
    概念:
        很多数据,都是跟时间有关,比如日志,都是按照时间顺序来产生的。
        分析数据,要按照时间求值
        
        interval  表示每一次求值的时间间隔
        width 时间窗口宽度,指每一次求值的时间窗口宽度

    当 width > interval 
    会出现重叠现象
    
    当 width = interval
    没有重叠现象
    
    当 width < interval
    数据会丢失。不采纳
    
    时序数据:
        日志、监控等产生的数据都是与时间相关的数据,
    按照时间先后产生并记录下来的数据,一般按照时间对数据进行分析
    
    数据分析基本程序解构:
        无限的生成随机数函数,产生时间相关的数据,返回时间+随机数
        每次取3个数据,求平均值
    例子:
    import random
    import datetime
    import time
    
    def source():
        while source():
            yield {'value':random.randint(1,100), 'datetime':datetime.datetime.now()}
            time.sleep(1)
    #获取数据
    s = source()
    items = [next(s) for _ in range(3)]
    
    #处理函数
    def handler(iterable):
        vals = [x['value'] for x in iterable]
        return sum(vals) / len(vals)
    print(items)
    print("{:.2f}".format(handle(items)))
    
    模拟一段时间内产生的数据,等一段固定的时间取数据来计算平均值
    
'''
import random
import time
import datetime


def source():
    while source():
        #随机值和时间 kv键对应
        yield {'value': random.randint(1, 100), 'datetime': datetime.datetime.now()}

def window(src, handler, width:int, interval:int):
    '''
    窗口函数
    :param src: 数据源,生成器,来取数据的
    :param handler: 数据处理函数
    :param width: 时间窗口宽度,秒
    :param interval: 处理时间间隔,秒
    :return:
    '''
# 迭代最上面的load(载入文件)函数 是个生成器 迭代出来的数据为字典,然后拿字段处理

    start = datetime.datetime.strptime('1970/01/01 01:01:01 +0800', "%Y/%m/%d %H:%M:%S %z")
    current = datetime.datetime.strptime('1970/01/01 01:01:01 +0800', "%Y/%m/%d %H:%M:%S %z")
    delta = datetime.timedelta(seconds=width - interval) # 重叠数据

    buffer = [] #缓冲区 待处理的数据
    for x in src:#迭代一批日志数据
        if x:#存入临时缓存等待计算
            buffer.append(x)#追加数据
            current = x['datetime'] #指日志中数据的时间指针的位置 一直在修改时间
        if (current - start).total_seconds() >= interval:
            ret = handler(buffer)
            print(ret)
            start = current #将时间间隔(interval)赋值给start

            buffer = [x for x in buffer if x['datetime'] > current - delta]#buffer处理


def donothing_handler(iterable:list):
    print(iterable)
    return iterable
#一批批数据进行处理
def handler(iterable:list): #字典处理

    return sum(iterable) // len(iterable)

window(load('c:/test.log'), donothing_handler, 10, 5)#载入日志文件 width10 interval5

  

posted @ 2017-11-04 21:59  zzzzz~  阅读(834)  评论(0编辑  收藏  举报