dispatch_user_class.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. #pragma DISPATCH_USER_CLASS_H
  2. #include <time.h>
  3. #include <iostream>
  4. #include "../error_code/error_code.h"
  5. #include "database_controller.h"
  6. class User_class
  7. {
  8. const int MAX_SQL_COMMAND_SIZE = 512U; // 最大sql命令长度
  9. const int DAYS_MIN_TIMES = 4; // 判断用户类型的最小认定次数
  10. const int MAX_SAVE_DAYS = 10*24*60*60; // 保留数据库表单时限
  11. const int WORKER_IN_TIME[4] = {6, 7, 9, 10}; // 通勤入库时间函数变量
  12. const int WORKER_OUT_TIME[4] = {16, 17, 19, 20}; // 通勤出库时间函数变量
  13. const int WORKER_PARK_TIME[2] = {3, 4}; // 通勤停车时长函数变量
  14. const int RESIDENT_IN_TIME[4] = {17, 18, 23, 24}; // 居民入库时间函数变量
  15. const int RESIDENT_OUT_TIME[4] = {5, 6, 8, 9}; // 居民出库时间函数变量
  16. const int RESIDENT_PARK_TIME[2] = {4, 5}; // 居民停车时长函数变量
  17. enum USER_CLASS {
  18. USER_CLASS_UNKNOW = 0, // 临时用户
  19. USER_CLASS_WORKER, // 通勤用户
  20. USER_CLASS_RESIDENT, // 居民用户
  21. USER_CLASS_STUDY,
  22. USER_CLASS_MON_CARD, // 月卡用户
  23. USER_CLASS_NO_STUDY,
  24. };
  25. private:
  26. /* data */
  27. public:
  28. User_class();
  29. ~User_class();
  30. public:
  31. static void test();
  32. bool is_vip(const std::string& car_number);
  33. Error_manager add_vip(std::string& car_number, time_t& start_time, time_t& end_time);
  34. Error_manager delete_vip(std::string& car_number);
  35. Error_manager update_vip(std::string& car_number, time_t start_time, time_t end_time);
  36. Error_manager update_table();
  37. Error_manager update_table(int save_time);
  38. int type(const std::string& car_number);
  39. Error_manager type(const std::string& car_number, int& user_type);
  40. Error_manager creat_table(const time_t& in_time, const time_t& out_time, const std::string& car_number);
  41. private:
  42. int time_t_2_int(const time_t& time);
  43. Error_manager statistics_table();
  44. Error_manager get_user_type(const std::string& car_number, int& user_type);
  45. double fuzzy_model_I(double a, double b, double x);
  46. double fuzzy_model_II(double a, double b, double c, double d, double x);
  47. private:
  48. std::string m_car_number;
  49. };
  50. User_class::User_class() {}
  51. User_class::~User_class() {}
  52. bool User_class::is_vip(const std::string& car_number)
  53. {
  54. boost::shared_ptr<sql::ResultSet> result;
  55. std::string sql_command = "select * from vip where car_number = '" + car_number + "'";
  56. Error_manager ec = Database_controller::get_instance_pointer()->sql_query(sql_command, result);
  57. if(result->next()) {
  58. time_t t = time(NULL);
  59. if (result->getInt("end_time") > time_t_2_int(t))
  60. return true;
  61. }
  62. return false;
  63. }
  64. Error_manager User_class::add_vip(std::string& car_number, time_t& start_time, time_t& end_time)
  65. {
  66. if (!is_vip(car_number)) {
  67. char sql_command[MAX_SQL_COMMAND_SIZE] = "";
  68. sprintf(sql_command, "insert into vip (start_time, end_time, car_number) values (%d, %d, '%s')\n", time_t_2_int(start_time), time_t_2_int(end_time), car_number.c_str());
  69. Error_manager ec = Database_controller::get_instance_pointer()->sql_insert(sql_command);
  70. } else {
  71. return update_vip(car_number, start_time, end_time);
  72. }
  73. return SUCCESS;
  74. }
  75. Error_manager User_class::delete_vip(std::string& car_number)
  76. {
  77. std::string sql_command = "delete from vip where car_number = '" + car_number + "'";
  78. Error_manager ec = Database_controller::get_instance_pointer()->sql_delete(sql_command);
  79. return SUCCESS;
  80. }
  81. Error_manager User_class::update_vip(std::string& car_number, time_t start_time, time_t end_time)
  82. {
  83. char sql_command[MAX_SQL_COMMAND_SIZE] = "";
  84. sprintf(sql_command, "update vip set start_time = %d, end_time = %d where car_number = '%s'", time_t_2_int(start_time), time_t_2_int(end_time), car_number.c_str());
  85. Error_manager ec = Database_controller::get_instance_pointer()->sql_update(sql_command);
  86. return SUCCESS;
  87. }
  88. int User_class::time_t_2_int(const time_t& time) {
  89. tm* tt = localtime(&time);
  90. return (tt->tm_year + 1900)*10000 + (tt->tm_mon + 1)*100 + tt->tm_mday;
  91. }
  92. // 对存储的近期用户数据进行综合统计
  93. Error_manager User_class::statistics_table()
  94. {
  95. // 删除旧的统计结果
  96. boost::shared_ptr<sql::ResultSet> result;
  97. std::string sql_command = "delete from user_class where record_time = 99999999 "; // 特殊id,用作记录统计数据;
  98. Error_manager ec = Database_controller::get_instance_pointer()->sql_delete(sql_command);
  99. std::cout << "---Debug--- delete statistics ec = " << ec << std::endl;
  100. // 获取全部车牌号
  101. sql_command = "select distinct car_number from user_class";
  102. ec = Database_controller::get_instance_pointer()->sql_query(sql_command, result);
  103. std::cout << "---Debug--- ec = " << ec << std::endl;
  104. // 对每个车牌重新判断用户类型,并添加到数据库
  105. while (result->next())
  106. {
  107. int user_type = USER_CLASS_UNKNOW;
  108. get_user_type(result->getString("car_number"), user_type);
  109. sql_command = "insert into user_class (record_time, user_type, car_number) values (99999999, " + std::to_string(user_type) + ", '" + result->getString("car_number") + "')";
  110. Database_controller::get_instance_pointer()->sql_insert(sql_command);
  111. }
  112. // 从数据库获取vip车辆信息,判断是否过期
  113. time_t t = time(NULL);
  114. sql_command = "select * from vip where end_time > " + std::to_string(time_t_2_int(t));
  115. ec = Database_controller::get_instance_pointer()->sql_query(sql_command, result);
  116. std::cout << "---Debug--- ec = " << ec << std::endl;
  117. while (result->next())
  118. {
  119. int user_type = USER_CLASS_UNKNOW;
  120. sql_command = "insert into user_class (record_time, user_type, car_number) values (99999999, " + std::to_string(USER_CLASS_MON_CARD) + ", '" + result->getString("car_number") + "')";
  121. ec = Database_controller::get_instance_pointer()->sql_insert(sql_command);
  122. }
  123. return ec;
  124. }
  125. // 第一类点对点模糊模型 a、b、按照从小到大顺序输入
  126. double User_class::fuzzy_model_I(double a, double b, double x)
  127. {
  128. if (x > a && x <= b)
  129. return 1.00 * ((x - a)/(b - a));
  130. else if (x > b)
  131. return 1;
  132. else
  133. return 0;
  134. }
  135. // 第二类点对点模糊模型 a、b、c、d、按照从小到大顺序输入
  136. double User_class::fuzzy_model_II(double a, double b, double c, double d, double x)
  137. {
  138. if (x > a && x <= b)
  139. return 1.00 *((x - a)/(b - a));
  140. else if (x > b && x <= c)
  141. return 1;
  142. else if (x > c && x <= d)
  143. return 1.00 * ((d - x)/(d - c));
  144. else
  145. return 0;
  146. }
  147. int User_class::type(const std::string& car_number) {
  148. int user_type = 0;
  149. type(car_number, user_type);
  150. return user_type;
  151. }
  152. Error_manager User_class::type(const std::string& car_number, int& user_type)
  153. {
  154. boost::shared_ptr<sql::ResultSet> result;
  155. std::string sql_command = "select * from user_class where record_time = 99999999 and car_number = '" + car_number + "'";
  156. Error_manager ec = Database_controller::get_instance_pointer()->sql_query(sql_command, result);
  157. if (result->next())
  158. {
  159. user_type = result->getInt("user_type");
  160. }
  161. return ec;
  162. }
  163. // 从数据库获取用户历史停留信息,并跟据信息判断用户类型;
  164. Error_manager User_class::get_user_type(const std::string& car_number, int& user_type)
  165. {
  166. int worker = 0, resident = 0;
  167. boost::shared_ptr<sql::ResultSet> result;
  168. std::string sql_command = "select * from user_class where user_type > 0 and user_type < 3 and car_number = '" + car_number + "'";
  169. Error_manager ec = Database_controller::get_instance_pointer()->sql_query(sql_command, result);
  170. while (result->next())
  171. {
  172. if (USER_CLASS_WORKER == result->getInt("user_type"))
  173. {
  174. worker++;
  175. }
  176. else
  177. {
  178. resident++;
  179. }
  180. }
  181. if (worker >= DAYS_MIN_TIMES && worker >= resident)
  182. {
  183. user_type = USER_CLASS_WORKER;
  184. }
  185. else if (resident >= DAYS_MIN_TIMES)
  186. {
  187. user_type = USER_CLASS_RESIDENT;
  188. }
  189. else
  190. {
  191. user_type = USER_CLASS_UNKNOW;
  192. }
  193. return ec;
  194. }
  195. // 跟据今日时间信息,删除默认设置天数以前的表单数据,更新数据库。
  196. Error_manager User_class::update_table()
  197. {
  198. return update_table(MAX_SAVE_DAYS);
  199. }
  200. // 跟据今日时间信息,删除设置天数以前的表单数据,更新数据库。todo:数据库操作判断
  201. Error_manager User_class::update_table(int save_time)
  202. {
  203. printf("---Debug--- Begain update table.\n");
  204. time_t t_now = time(NULL) - save_time;
  205. std::string sql_command = "delete from user_class where record_time < " + std::to_string(time_t_2_int(t_now));
  206. Error_manager ec = Database_controller::get_instance_pointer()->sql_delete(sql_command);
  207. std::cout << "---Debug--- delete old ec = " << ec << std::endl;
  208. statistics_table();
  209. printf("---Debug--- update table over.\n");
  210. return ec;
  211. }
  212. // 通过传入的车辆入库、出库时间,计算隶属度,判断用户类型,然后存入到数据库;
  213. Error_manager User_class::creat_table(const time_t& in_time, const time_t& out_time, const std::string& car_number)
  214. {
  215. if(is_vip(car_number)) {
  216. return SUCCESS;
  217. }
  218. // 计算
  219. tm out = *localtime(&out_time);
  220. int user_type = USER_CLASS_UNKNOW;
  221. double parking_time = (out_time - in_time)/3600.00;
  222. double f_in = localtime(&in_time)->tm_hour + localtime(&in_time)->tm_min/60.00;
  223. double f_out = localtime(&out_time)->tm_hour + localtime(&out_time)->tm_min/60.00;
  224. // 根据入库时间计算隶属度
  225. double s_worker_in, s_worker_out, s_worker_park, s_resident_in, s_resident_out, s_resident_park;
  226. double s_worker, s_resident;
  227. s_worker_in = fuzzy_model_II(WORKER_IN_TIME[0], WORKER_IN_TIME[1], WORKER_IN_TIME[2], WORKER_IN_TIME[3], f_in);
  228. s_worker_out = fuzzy_model_II(WORKER_OUT_TIME[0], WORKER_OUT_TIME[1], WORKER_OUT_TIME[2], WORKER_OUT_TIME[3], f_out);
  229. s_worker_park = fuzzy_model_I(WORKER_PARK_TIME[0], WORKER_PARK_TIME[1], parking_time);
  230. s_resident_in = fuzzy_model_II(RESIDENT_IN_TIME[0], RESIDENT_IN_TIME[1], RESIDENT_IN_TIME[2], RESIDENT_IN_TIME[3], f_in);
  231. s_resident_out = fuzzy_model_II(RESIDENT_OUT_TIME[0], RESIDENT_OUT_TIME[1], RESIDENT_OUT_TIME[2], RESIDENT_OUT_TIME[3], f_out);
  232. s_resident_park = fuzzy_model_I(RESIDENT_PARK_TIME[0], RESIDENT_PARK_TIME[1], parking_time);
  233. s_worker = s_worker_in + s_worker_out + s_worker_park;
  234. s_resident = s_resident_in + s_resident_out + s_resident_park;
  235. // 根据隶属度判断用户类型
  236. if (s_worker >= s_resident && s_worker > 1.5)
  237. {
  238. user_type = USER_CLASS_WORKER;
  239. }
  240. else if (s_resident >= s_worker && s_resident > 1.5)
  241. {
  242. user_type = USER_CLASS_RESIDENT;
  243. }
  244. // 存储车牌、用户类型、日期、到sql
  245. char sql_command[MAX_SQL_COMMAND_SIZE] = "";
  246. sprintf(sql_command, "insert into user_class (car_number, record_time, user_type) values ('%s', %d, %d)",
  247. car_number.c_str(), time_t_2_int(out_time), user_type);
  248. Error_manager ec = Database_controller::get_instance_pointer()->sql_insert(sql_command);
  249. return SUCCESS;
  250. }
  251. void User_class::test()
  252. {
  253. User_class user_class;
  254. user_class.update_table();
  255. int times = 0;
  256. while (true && ++times)
  257. {
  258. printf("-----> No.%d start <-----\n", times);
  259. // 随机车牌、入场时间、停车时间
  260. time_t a = time(NULL);
  261. tm *tt = localtime(&a);
  262. tt->tm_sec = rand() % 61;
  263. tt->tm_min = rand() % 61;
  264. tt->tm_hour = rand() % 25;
  265. tt->tm_mday -= rand()%11 ; // 随机日期,最近十天
  266. time_t in = mktime(tt);
  267. time_t out = in + rand()%(24*60*60 + 1); // 最长停留一天
  268. // std::string car_number = "鄂A" + std::to_string(rand()%90000 + 10000); // 车牌
  269. std::string car_number = "鄂A900" + std::to_string(rand()%90 + 10); // 车牌
  270. // std::string car_number = "鄂A98829";
  271. // 添加记录到表格
  272. user_class.creat_table(in, out, car_number);
  273. // 获取该车牌类型
  274. int user_type = user_class.type(car_number);
  275. std::cout << "---Debug--- " << car_number << " check user_type " << user_type << std::endl;
  276. time_t end = in + 30*24*60*60;
  277. if (user_type < USER_CLASS_STUDY && user_type > USER_CLASS_UNKNOW) {
  278. user_class.add_vip(car_number, in, end);
  279. } else if (user_type == USER_CLASS_MON_CARD) {
  280. user_class.update_vip(car_number, in, end);
  281. }
  282. printf("-----> No.%d end <-----\n", times);
  283. sleep(1);
  284. }
  285. }