EquipmentInfoService.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. # -*- encoding: utf-8 -*-
  2. """
  3. @File : EquipmentInfoService.py
  4. @Time : 2022/4/14 17:28
  5. @Author : stephen
  6. @Email : zhangdongming@asj6.wecom.work
  7. @Software: PyCharm
  8. """
  9. import datetime
  10. import time
  11. import itertools
  12. from django.db.models import Value, CharField
  13. from Model.models import EquipmentInfoMonday, EquipmentInfoTuesday, EquipmentInfoWednesday, EquipmentInfoThursday, \
  14. EquipmentInfoFriday, EquipmentInfoSaturday, EquipmentInfoSunday
  15. from Object.utils import LocalDateTimeUtil
  16. """
  17. 设备分表查询Service
  18. 因数据量不断增加,单表保留近七天数据进行分表优化设计
  19. 进行拆分为七张表星期一至星期天进行分表存储。分担单表存储读写压力。
  20. """
  21. class EquipmentInfoService:
  22. @staticmethod
  23. def get_equipment_info_model(dt, val=0):
  24. """
  25. 根据日期判断是星期几,返回相应的Model对象
  26. @param val: 1-7代表week
  27. @param dt: 日期 例:2022-03-03
  28. @return: 星期一至星期天equipment_info对象实例
  29. """
  30. week = 1
  31. if dt:
  32. week = LocalDateTimeUtil.date_to_week(dt)
  33. if 0 < val < 8:
  34. week = val
  35. equipment_info = None
  36. if week == 1:
  37. equipment_info = EquipmentInfoMonday.objects.all().annotate(tab_val=Value('1', output_field=CharField()))
  38. elif week == 2:
  39. equipment_info = EquipmentInfoTuesday.objects.all().annotate(tab_val=Value('2', output_field=CharField()))
  40. elif week == 3:
  41. equipment_info = EquipmentInfoWednesday.objects.all().annotate(tab_val=Value('3', output_field=CharField()))
  42. elif week == 4:
  43. equipment_info = EquipmentInfoThursday.objects.all().annotate(tab_val=Value('4', output_field=CharField()))
  44. elif week == 5:
  45. equipment_info = EquipmentInfoFriday.objects.all().annotate(tab_val=Value('5', output_field=CharField()))
  46. elif week == 6:
  47. equipment_info = EquipmentInfoSaturday.objects.all().annotate(tab_val=Value('6', output_field=CharField()))
  48. elif week == 7:
  49. equipment_info = EquipmentInfoSunday.objects.all().annotate(tab_val=Value('7', output_field=CharField()))
  50. return equipment_info
  51. @classmethod
  52. def find_by_start_time_equipment_info(cls, page, size, user_id, start_time, end_time, event_type,
  53. uid_list):
  54. """
  55. 通过start_time查找指定日期当天设备消息推送
  56. @param page: 页数
  57. @param size: 每页条数
  58. @param user_id: 设备用户id
  59. @param start_time: 开始时间
  60. @param end_time: 结束时间
  61. @param event_type: 事件类型
  62. @param uid_list: 设备uid列表
  63. @return: result 查询结果
  64. """
  65. if start_time and end_time:
  66. start_date = datetime.datetime.fromtimestamp(int(start_time))
  67. # 根据开始日期,获取设备信息查询对象
  68. qs = EquipmentInfoService.get_equipment_info_model(str(start_date.date()), 0)
  69. # 调用查询方法
  70. qs = cls.query_equipment_info(qs, user_id, start_time, end_time, event_type,
  71. uid_list)
  72. # 时区问题
  73. week = LocalDateTimeUtil.date_to_week(str(start_date.date()))
  74. if week > 0:
  75. # 根据筛选日期 查找昨天数据
  76. yesterday = 7 if week == 1 else week - 1
  77. yesterday_info = EquipmentInfoService.get_equipment_info_model('', yesterday)
  78. yesterday_info = cls.query_equipment_info(yesterday_info, user_id, start_time, end_time, event_type,
  79. uid_list)
  80. # 根据筛选日期 查找明天数据
  81. tomorrow = 1 if week == 7 else week + 1
  82. tomorrow_info = EquipmentInfoService.get_equipment_info_model('', tomorrow)
  83. tomorrow_info = cls.query_equipment_info(tomorrow_info, user_id, start_time, end_time, event_type,
  84. uid_list)
  85. qs = qs.union(yesterday_info, tomorrow_info, all=True)
  86. if qs.exists():
  87. count = qs.count()
  88. qs_page = cls.get_equipment_info_page(qs, page, size)
  89. return qs_page, count
  90. return None, 0
  91. @classmethod
  92. def get_equipment_info_week_all(cls, page, size, user_id, start_time, end_time, event_type,
  93. uid_list):
  94. """
  95. 分表查询近七天设备消息推送
  96. @param page: 页数
  97. @param size: 分页大小
  98. @param user_id: 设备用户id
  99. @param start_time: 事件开始时间
  100. @param end_time: 事件结束时间
  101. @param event_type: 事件类型
  102. @param uid_list: uid列表
  103. @return: qs_page, count 结果集
  104. """
  105. # 星期一设备信息查询
  106. monday_qs = EquipmentInfoService.get_equipment_info_model('', 1)
  107. monday_qs = cls.query_equipment_info(monday_qs, user_id, start_time, end_time, event_type,
  108. uid_list)
  109. # 星期二设备信息查询
  110. tuesday_qs = EquipmentInfoService.get_equipment_info_model('', 2)
  111. tuesday_qs = cls.query_equipment_info(tuesday_qs, user_id, start_time, end_time, event_type,
  112. uid_list)
  113. # 星期三设备信息查询
  114. wednesday_qs = EquipmentInfoService.get_equipment_info_model('', 3)
  115. wednesday_qs = cls.query_equipment_info(wednesday_qs, user_id, start_time, end_time, event_type,
  116. uid_list)
  117. # 星期四设备信息查询
  118. thursday_qs = EquipmentInfoService.get_equipment_info_model('', 4)
  119. thursday_qs = cls.query_equipment_info(thursday_qs, user_id, start_time, end_time, event_type,
  120. uid_list)
  121. # 星期五设备信息查询
  122. friday_qs = EquipmentInfoService.get_equipment_info_model('', 5)
  123. friday_qs = cls.query_equipment_info(friday_qs, user_id, start_time, end_time, event_type,
  124. uid_list)
  125. # 星期六设备信息查询
  126. saturday_qs = EquipmentInfoService.get_equipment_info_model('', 6)
  127. saturday_qs = cls.query_equipment_info(saturday_qs, user_id, start_time, end_time, event_type,
  128. uid_list)
  129. # 星期天设备信息查询
  130. sunday_qs = EquipmentInfoService.get_equipment_info_model('', 7)
  131. sunday_qs = cls.query_equipment_info(sunday_qs, user_id, start_time, end_time, event_type,
  132. uid_list)
  133. result = monday_qs.union(tuesday_qs, wednesday_qs, thursday_qs, friday_qs, saturday_qs, sunday_qs, all=True)
  134. count = result.count()
  135. qs_page = cls.get_equipment_info_page(result, page, size)
  136. return qs_page, count
  137. @classmethod
  138. def query_equipment_info(cls, qs, user_id, start_time, end_time, event_type,
  139. uid_list):
  140. """
  141. 设备信息条件查询,根据分表设计,默认条件event_time大于七天前时间
  142. @param qs: 设备信息查询对象
  143. @param user_id: 设备用户id
  144. @param start_time: 开始时间
  145. @param end_time: 结束时间
  146. @param event_type: 事件类型
  147. @param uid_list: 设备uid列表
  148. @return: result 设备信息结果集
  149. """
  150. now_time = int(time.time())
  151. # 获取七天前时间戳
  152. seven_days_before_time = LocalDateTimeUtil.get_before_days_timestamp(now_time, 7)
  153. # 默认查询当前表event_time大于七天前时间
  154. qs = qs.filter(event_time__gt=seven_days_before_time)
  155. if user_id:
  156. qs = qs.filter(device_user_id=user_id)
  157. if event_type:
  158. # 多类型查询
  159. if ',' in event_type:
  160. eventTypeList = cls.get_comb_event_type(event_type)
  161. qs = qs.filter(event_type__in=eventTypeList)
  162. else:
  163. qs = qs.filter(event_type=event_type)
  164. if start_time and end_time:
  165. qs = qs.filter(event_time__range=(start_time, end_time))
  166. if uid_list:
  167. uid_list = uid_list.split(',')
  168. qs = qs.filter(device_uid__in=uid_list)
  169. return qs
  170. @classmethod
  171. def get_equipment_info_page(cls, equipment_info_qs, page, size):
  172. """
  173. 获取查询结果集进行排序、分页,遍历重命名字典key(主要针对原函数返回结果集)
  174. @param equipment_info_qs: 设备信息结果集
  175. @param page: 页数
  176. @param size: 分页大小
  177. @return: qs_page 遍历后的设备信息结果集
  178. """
  179. equipment_info_qs = equipment_info_qs.values('id', 'device_uid', 'device_nick_name', 'channel', 'event_type',
  180. 'status', 'alarm',
  181. 'event_time', 'receive_time', 'is_st', 'add_time',
  182. 'storage_location', 'border_coords', 'tab_val')
  183. equipment_info_qs = equipment_info_qs.order_by('-event_time')
  184. qs_page = equipment_info_qs[(page - 1) * size:page * size]
  185. if not qs_page or not qs_page.exists() or qs_page.count == 0:
  186. return qs_page
  187. for item in qs_page:
  188. # 星期表值
  189. tab_val = item['tab_val']
  190. # id = 星期表值+id
  191. item['id'] = int(tab_val + str(item['id']))
  192. item['devUid'] = item['device_uid']
  193. item['devNickName'] = item['device_nick_name']
  194. item['Channel'] = item['channel']
  195. item['eventType'] = item['event_type']
  196. item['eventTime'] = item['event_time']
  197. item['receiveTime'] = item['receive_time']
  198. item['addTime'] = item['add_time']
  199. item['borderCoords'] = item['border_coords']
  200. item.pop('device_uid')
  201. item.pop('device_nick_name')
  202. item.pop('channel')
  203. item.pop('event_type')
  204. item.pop('event_time')
  205. item.pop('receive_time')
  206. item.pop('add_time')
  207. item.pop('border_coords')
  208. item.pop('tab_val')
  209. return qs_page
  210. @classmethod
  211. def get_comb_event_type(cls, event_type):
  212. """
  213. 重新组合ai消息类型查询,使其支持ai多标签查询
  214. @param event_type: 消息类型
  215. @return: event_type_list 消息类型数组
  216. """
  217. event_type_list = event_type.split(',')
  218. event_type_list = [int(i.strip()) for i in event_type_list]
  219. ai_event_type_list = []
  220. for key, val in enumerate(event_type_list):
  221. if val <= 4: # 分离出ai类型,以便后续组合ai标签,目前只存在4个ai类型1,2,3,4
  222. ai_event_type_list.append(val)
  223. del (event_type_list[key])
  224. if len(ai_event_type_list) < 1:
  225. return event_type_list
  226. ai_event_type_list.sort()
  227. type = [1, 2, 3, 4] # AI目前所有的标签,1人,2车,3宠物,4包裹,后续有新类型需要这里加
  228. comb_ai_event_type = []
  229. seen = set()
  230. for i in range(1, len(type) + 1): # 计算所有组合,如[1, 2, 3, 4], 4取1,4取2,4取3,4取4
  231. for s in itertools.combinations(type, i):
  232. if s not in seen: # 去除重复项, 如a=[1,2,3,4,4],会有两个[1,2,3,4,4],[1,2,3,4,4]的组合
  233. seen.add(s)
  234. s_list = list(s)
  235. for ai_event_type in ai_event_type_list:
  236. if ai_event_type in s_list: # 排除没有选择的标签组合
  237. if s_list not in comb_ai_event_type:
  238. s_list = [str(v) for v in s_list]
  239. comb_ai_event_type.append(s_list)
  240. regroup_list = []
  241. for val in comb_ai_event_type: # 组合ai类型组合,如[[2,3],[1,3]] -> [23, 13]
  242. val = ''.join(val)
  243. regroup_list.append(int(val))
  244. event_type_list = regroup_list + event_type_list # 加上普通移动消息类型
  245. return event_type_list