问题场景
- 数据量较大, 数据有排序的根据(我这里是推文, 根据粉丝数量进行排序)
- 数据可能无法全部读取进内存
- 根据推文, 找出粉丝数量前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的排序
主要针对于内存大小有限制的场景, 小数据, 直接放入内存排序就行