python大数据实现top k问题

问题场景

  • 数据量较大, 数据有排序的根据(我这里是推文, 根据粉丝数量进行排序)
  • 数据可能无法全部读取进内存
  • 根据推文, 找出粉丝数量前300的用户

问题解决

  • 对于大量的推文, 先对其进行划分, 将它们划分到多个小的文件, 保证每个文件都能轻松放进内存
  • 挨个读取推文, 用小顶堆来存储前k个用户, 堆容量小于k, 就直接放入, 如果大于, 则与堆顶(最小)元素进行比较, 大者入堆
  • 最终将堆中元素输出即可

因为之前都是用的java, python这边不是很熟悉


from queue import PriorityQueue as PQ
import pymongo
from pymongo import MongoClient

class User():
    def __init__(self, id, screen_name,name, followers_count,text):
        self.id = id
        self.screen_name = screen_name
        self.name = name
        self.followers_count = followers_count
        self.text = text


    # 类似于java中的compare方法
    def __lt__(self, other):
        return self.followers_count < other.followers_count

myclient = pymongo.MongoClient("mongodb://localhost:27017/")
mydb = myclient['######']

collectionNames = mydb.collection_names()

users = set()
pq = PQ() ## 优先队列
for name in collectionNames:
    collection = mydb[name]
    for doc in collection.find():
        user = doc['user']
        cur = User(user['id'],user["screen_name"],user['name'],user["followers_count"],doc['text'])
        # followers_count = user["followers_count"]
        # screenName = user["screen_name"]
        if cur.id in users: continue
        if pq.qsize()<300:
            pq.put(cur)
            users.add(cur.id)
        else:
            min = pq.get() 
            # print(min)
            if min.followers_count <=cur.followers_count:
                min = cur
                users.add(cur.id)
            pq.put(min)

size = pq.qsize()
data = []
while size>0:
    cur = pq.get() # 当优先队里为空时, 会阻塞, 算是一个阻塞队列
    print("id: "+str(cur.id))
    print("followers_count: "+str(cur.followers_count))
    print("screen_name: "+str(cur.screen_name))
    print("name: " + str(cur.name))
    print("text: " + str(cur.text))
    print("=======================")
    size -= 1
    print(size)
    data.append(cur.name)

data.reverse() # 翻转一下
  • 使用python中提供的PriorityQueue来实现, 这里和java的逻辑不太一样
  • 默认是小顶堆, get方法是个阻塞方法(可以用来实现生产者消费者模型), 且似乎没有类似于peek这样的方法, 所以我就先取出, 再放入, 有点麻烦
  • put方法放入元素, 可以放入tuple, 但是顺序的比较是, 依次比较tuple中的每个元素, 如果出现元素不能compare的, 就会报错TypeError: '<' not supported between instances of 'dict' and 'dict'
  • 所以这里解决比较的方法, 我认为最方便的, 就是新建一个类, 将信息放入, 然后重写__lt__(self, other)方法, 便可以解决比较的问题
  • PriorityQueue是优先队列, 不算是堆其实, 复杂度比堆要高, 但是能得到top k的排序

主要针对于内存大小有限制的场景, 小数据, 直接放入内存排序就行

猜你喜欢

转载自blog.csdn.net/qq_34687559/article/details/119925203