From 289fb7690643ba45b6e5f42a1b740b36d629716a Mon Sep 17 00:00:00 2001 From: Dmitriy Simushev Date: Tue, 7 May 2013 11:25:21 +0000 Subject: [PATCH] Refactor cron_calculate_statistics function --- src/messenger/webim/cron.php | 7 +- src/messenger/webim/libs/cron.php | 198 ------------------- src/messenger/webim/libs/statistics.php | 245 ++++++++++++++++++++++++ 3 files changed, 251 insertions(+), 199 deletions(-) diff --git a/src/messenger/webim/cron.php b/src/messenger/webim/cron.php index 2018457a..35832333 100644 --- a/src/messenger/webim/cron.php +++ b/src/messenger/webim/cron.php @@ -19,6 +19,7 @@ require_once('libs/init.php'); require_once('libs/classes/thread.php'); require_once('libs/track.php'); +require_once('libs/statistics.php'); require_once('libs/cron.php'); $cron_key = empty($_GET['cron_key']) ? '' : $_GET['cron_key']; @@ -32,7 +33,11 @@ set_time_limit(0); // Run cron jobs of the core cron_index_messages(); -cron_calculate_statistics(); + +calculate_thread_statistics(); +calculate_operator_statistics(); +calculate_page_statistics(); + // Trigger cron event $dispatcher = EventDispatcher::getInstance(); diff --git a/src/messenger/webim/libs/cron.php b/src/messenger/webim/libs/cron.php index 2d758b9d..b886c827 100644 --- a/src/messenger/webim/libs/cron.php +++ b/src/messenger/webim/libs/cron.php @@ -202,204 +202,6 @@ function cron_index_messages() { $db->query('COMMIT'); } -/** - * Calculate aggregated 'by thread' and 'by operator' statistics - */ -function cron_calculate_statistics() { - // Prepare database - $db = Database::getInstance(); - $db->throwExeptions(true); - - try { - // Start transaction - $db->query('START TRANSACTION'); - - // Build 'by thread' statistics - // Get last record date - $result = $db->query( - "SELECT MAX(date) as start FROM {chatthreadstatistics}", - array(), - array('return_rows' => Database::RETURN_ONE_ROW) - ); - - $start = empty($result['start']) ? 0 : $result['start']; - - // Reset statistics for the last day, because cron can be ran many - // times in a day. - $result = $db->query( - "DELETE FROM {chatthreadstatistics} WHERE date = :start", - array(':start' => $start) - ); - - // Calculate 'by thread' statistics - $db->query( - "INSERT INTO {chatthreadstatistics} ( " . - "date, threads, operatormessages, usermessages, " . - "averagewaitingtime, averagechattime " . - ") SELECT (FLOOR(t.dtmcreated / (24*60*60)) * 24*60*60) AS date, " . - "COUNT(distinct t.threadid) AS threads, " . - "SUM(m.ikind = :kind_agent) AS operators, " . - "SUM(m.ikind = :kind_user) AS users, " . - "ROUND(AVG(t.dtmchatstarted-t.dtmcreated),1) as avgwaitingtime, " . - // Prevent negative values of avgchattime field. - // If avgchattime < 0 it becomes to zero. - // For random value 'a' result of expression ((abs(a) + a) / 2) - // equals to 'a' if 'a' more than zero - // and equals to zero otherwise - "ROUND(AVG( " . - "ABS(tmp.lastmsgtime-t.dtmchatstarted) + " . - "(tmp.lastmsgtime-t.dtmchatstarted) " . - ")/2,1) as avgchattime " . - "FROM {indexedchatmessage} m, " . - "{chatthread} t, " . - "(SELECT i.threadid, MAX(i.dtmcreated) AS lastmsgtime " . - "FROM {indexedchatmessage} i " . - "WHERE (ikind = :kind_user OR ikind = :kind_agent) " . - "GROUP BY i.threadid) tmp " . - "WHERE m.threadid = t.threadid " . - "AND tmp.threadid = t.threadid " . - "AND t.dtmchatstarted <> 0 " . - "AND m.dtmcreated > :start " . - "GROUP BY date " . - "ORDER BY date", - array( - ':kind_agent' => Thread::KIND_AGENT, - ':kind_user' => Thread::KIND_USER, - ':start' => $start - ) - ); - - // Build 'by operator' statistics - // Get last record date - $result = $db->query( - "SELECT MAX(date) as start FROM {chatoperatorstatistics}", - array(), - array('return_rows' => Database::RETURN_ONE_ROW) - ); - - $start = empty($result['start']) ? 0 : $result['start']; - - // Reset statistics for the last day, because cron can be ran many - // times in a day. - $result = $db->query( - "DELETE FROM {chatoperatorstatistics} WHERE date = :start", - array(':start' => $start) - ); - - // Caclculate 'by operator' statistics - $db->query( - "INSERT INTO {chatoperatorstatistics} ( " . - "date, operatorid, threads, messages, averagelength" . - ") SELECT (FLOOR(m.dtmcreated / (24*60*60)) * 24*60*60) AS date, " . - "o.operatorid AS opid, " . - "COUNT(distinct m.threadid) AS threads, " . - "SUM(m.ikind = :kind_agent) AS msgs, " . - "AVG(CHAR_LENGTH(m.tmessage)) AS avglen " . - "FROM {indexedchatmessage} m, {chatoperator} o " . - "WHERE m.agentId = o.operatorid " . - "AND m.dtmcreated > :start " . - "GROUP BY date " . - "ORDER BY date", - array( - ':kind_agent' => Thread::KIND_AGENT, - ':start' => $start - ) - ); - - // Build 'by page' statistics - $visited_pages = $db->query( - "SELECT FLOOR(p.visittime / (24*60*60)) * 24*60*60 AS date, " . - "p.address AS address, " . - // 'visittimes' is not calculated pages count. It means that - // 'visittimes' is count of NEW visited pages, not total count. - "COUNT(DISTINCT p.pageid) AS visittimes, " . - // 'chattimes' is total count of threads related with a page - // address, not a visited page row. It means that 'chattimes' is - // TOTAL chats count from this page, not only new. - "COUNT(DISTINCT t.threadid) AS chattimes " . - "FROM {visitedpage} p " . - "LEFT OUTER JOIN {chatthread} t ON (" . - "p.address = t.referer " . - "AND DATE(FROM_UNIXTIME(p.visittime)) = " . - "DATE(FROM_UNIXTIME(t.dtmcreated))) " . - "WHERE p.calculated = 0 " . - "GROUP BY date, address " . - "ORDER BY date", - array(), - array('return_rows' => Database::RETURN_ALL_ROWS) - ); - - foreach($visited_pages as $visited_page) { - // Check is there statistics for current visited page in database. - $count_result = $db->query( - "SELECT COUNT(*) AS count " . - "FROM {visitedpagestatistics} " . - "WHERE date = :date AND address = :address", - array( - ':date' => $visited_page['date'], - ':address' => $visited_page['address'] - ), - array('return_rows' => Database::RETURN_ONE_ROW) - ); - - if (! empty($count_result['count'])) { - // Stat already in database. Update it. - $db->query( - "UPDATE {visitedpagestatistics} SET " . - "visits = visits + :visits, " . - // Do not add chat because of it is total count of chats - // related with this page. - // TODO: Think about old threads removing. In current - // configuration it can cause problems with wrong - // 'by page' statistics. - "chats = :chats " . - "WHERE date = :date " . - "AND address = :address " . - "LIMIT 1", - array( - ':date' => $visited_page['date'], - ':address' => $visited_page['address'], - ':visits' => $visited_page['visittimes'], - ':chats' => $visited_page['chattimes'] - ) - ); - } else { - // Create stat row in database. - $db->query( - "INSERT INTO {visitedpagestatistics} (" . - "date, address, visits, chats" . - ") VALUES ( " . - ":date, :address, :visits, :chats" . - ")", - array( - ':date' => $visited_page['date'], - ':address' => $visited_page['address'], - ':visits' => $visited_page['visittimes'], - ':chats' => $visited_page['chattimes'] - ) - ); - } - } - - // Mark all visited pages as 'calculated' - $db->query("UPDATE {visitedpage} SET calculated = 1"); - - // Remove old tracks from the system - track_remove_old_tracks(); - } catch(Exception $e) { - // Something went wrong: warn and rollback transaction. - trigger_error( - 'Statistics calculating faild: ' . $e->getMessage(), - E_USER_WARNING - ); - $db->query('ROLLBACK'); - return; - } - - // Commit transaction - $db->query('COMMIT'); -} - /** * Generates cron URI * diff --git a/src/messenger/webim/libs/statistics.php b/src/messenger/webim/libs/statistics.php index 8520378b..959fd05d 100644 --- a/src/messenger/webim/libs/statistics.php +++ b/src/messenger/webim/libs/statistics.php @@ -39,4 +39,249 @@ function setup_statistics_tabs($active) } } +/** + * Calculate aggregated 'by thread' statistics + */ +function calculate_thread_statistics() { + // Prepare database + $db = Database::getInstance(); + $db->throwExeptions(true); + + try { + // Start transaction + $db->query('START TRANSACTION'); + + // Get last record date + $result = $db->query( + "SELECT MAX(date) as start FROM {chatthreadstatistics}", + array(), + array('return_rows' => Database::RETURN_ONE_ROW) + ); + + $start = empty($result['start']) ? 0 : $result['start']; + + // Reset statistics for the last day, because cron can be ran many + // times in a day. + $result = $db->query( + "DELETE FROM {chatthreadstatistics} WHERE date = :start", + array(':start' => $start) + ); + + // Calculate statistics + $db->query( + "INSERT INTO {chatthreadstatistics} ( " . + "date, threads, operatormessages, usermessages, " . + "averagewaitingtime, averagechattime " . + ") SELECT (FLOOR(t.dtmcreated / (24*60*60)) * 24*60*60) AS date, " . + "COUNT(distinct t.threadid) AS threads, " . + "SUM(m.ikind = :kind_agent) AS operators, " . + "SUM(m.ikind = :kind_user) AS users, " . + "ROUND(AVG(t.dtmchatstarted-t.dtmcreated),1) as avgwaitingtime, " . + // Prevent negative values of avgchattime field. + // If avgchattime < 0 it becomes to zero. + // For random value 'a' result of expression ((abs(a) + a) / 2) + // equals to 'a' if 'a' more than zero + // and equals to zero otherwise + "ROUND(AVG( " . + "ABS(tmp.lastmsgtime-t.dtmchatstarted) + " . + "(tmp.lastmsgtime-t.dtmchatstarted) " . + ")/2,1) as avgchattime " . + "FROM {indexedchatmessage} m, " . + "{chatthread} t, " . + "(SELECT i.threadid, MAX(i.dtmcreated) AS lastmsgtime " . + "FROM {indexedchatmessage} i " . + "WHERE (ikind = :kind_user OR ikind = :kind_agent) " . + "GROUP BY i.threadid) tmp " . + "WHERE m.threadid = t.threadid " . + "AND tmp.threadid = t.threadid " . + "AND t.dtmchatstarted <> 0 " . + "AND m.dtmcreated > :start " . + "GROUP BY date " . + "ORDER BY date", + array( + ':kind_agent' => Thread::KIND_AGENT, + ':kind_user' => Thread::KIND_USER, + ':start' => $start + ) + ); + } catch(Exception $e) { + // Something went wrong: warn and rollback transaction. + trigger_error( + 'Thread statistics calculating faild: ' . $e->getMessage(), + E_USER_WARNING + ); + $db->query('ROLLBACK'); + return; + } + + // Commit transaction + $db->query('COMMIT'); +} + +/** + * Calculate aggregated 'by operator' statistics + */ +function calculate_operator_statistics() { + // Prepare database + $db = Database::getInstance(); + $db->throwExeptions(true); + + try { + // Start transaction + $db->query('START TRANSACTION'); + + // Get last record date + $result = $db->query( + "SELECT MAX(date) as start FROM {chatoperatorstatistics}", + array(), + array('return_rows' => Database::RETURN_ONE_ROW) + ); + + $start = empty($result['start']) ? 0 : $result['start']; + + // Reset statistics for the last day, because cron can be ran many + // times in a day. + $result = $db->query( + "DELETE FROM {chatoperatorstatistics} WHERE date = :start", + array(':start' => $start) + ); + + // Caclculate statistics + $db->query( + "INSERT INTO {chatoperatorstatistics} ( " . + "date, operatorid, threads, messages, averagelength" . + ") SELECT (FLOOR(m.dtmcreated / (24*60*60)) * 24*60*60) AS date, " . + "o.operatorid AS opid, " . + "COUNT(distinct m.threadid) AS threads, " . + "SUM(m.ikind = :kind_agent) AS msgs, " . + "AVG(CHAR_LENGTH(m.tmessage)) AS avglen " . + "FROM {indexedchatmessage} m, {chatoperator} o " . + "WHERE m.agentId = o.operatorid " . + "AND m.dtmcreated > :start " . + "GROUP BY date " . + "ORDER BY date", + array( + ':kind_agent' => Thread::KIND_AGENT, + ':start' => $start + ) + ); + } catch(Exception $e) { + // Something went wrong: warn and rollback transaction. + trigger_error( + 'Operator statistics calculating faild: ' . $e->getMessage(), + E_USER_WARNING + ); + $db->query('ROLLBACK'); + return; + } + + // Commit transaction + $db->query('COMMIT'); +} + +/** + * Calculate aggregated 'by page' statistics + */ +function calculate_page_statistics() { + // Prepare database + $db = Database::getInstance(); + $db->throwExeptions(true); + + try { + // Start transaction + $db->query('START TRANSACTION'); + + $visited_pages = $db->query( + "SELECT FLOOR(p.visittime / (24*60*60)) * 24*60*60 AS date, " . + "p.address AS address, " . + // 'visittimes' is not calculated pages count. It means that + // 'visittimes' is count of NEW visited pages, not total count. + "COUNT(DISTINCT p.pageid) AS visittimes, " . + // 'chattimes' is total count of threads related with a page + // address, not a visited page row. It means that 'chattimes' is + // TOTAL chats count from this page, not only new. + "COUNT(DISTINCT t.threadid) AS chattimes " . + "FROM {visitedpage} p " . + "LEFT OUTER JOIN {chatthread} t ON (" . + "p.address = t.referer " . + "AND DATE(FROM_UNIXTIME(p.visittime)) = " . + "DATE(FROM_UNIXTIME(t.dtmcreated))) " . + "WHERE p.calculated = 0 " . + "GROUP BY date, address " . + "ORDER BY date", + array(), + array('return_rows' => Database::RETURN_ALL_ROWS) + ); + + foreach($visited_pages as $visited_page) { + // Check is there statistics for current visited page in database. + $count_result = $db->query( + "SELECT COUNT(*) AS count " . + "FROM {visitedpagestatistics} " . + "WHERE date = :date AND address = :address", + array( + ':date' => $visited_page['date'], + ':address' => $visited_page['address'] + ), + array('return_rows' => Database::RETURN_ONE_ROW) + ); + + if (! empty($count_result['count'])) { + // Stat already in database. Update it. + $db->query( + "UPDATE {visitedpagestatistics} SET " . + "visits = visits + :visits, " . + // Do not add chat because of it is total count of chats + // related with this page. + // TODO: Think about old threads removing. In current + // configuration it can cause problems with wrong + // 'by page' statistics. + "chats = :chats " . + "WHERE date = :date " . + "AND address = :address " . + "LIMIT 1", + array( + ':date' => $visited_page['date'], + ':address' => $visited_page['address'], + ':visits' => $visited_page['visittimes'], + ':chats' => $visited_page['chattimes'] + ) + ); + } else { + // Create stat row in database. + $db->query( + "INSERT INTO {visitedpagestatistics} (" . + "date, address, visits, chats" . + ") VALUES ( " . + ":date, :address, :visits, :chats" . + ")", + array( + ':date' => $visited_page['date'], + ':address' => $visited_page['address'], + ':visits' => $visited_page['visittimes'], + ':chats' => $visited_page['chattimes'] + ) + ); + } + } + + // Mark all visited pages as 'calculated' + $db->query("UPDATE {visitedpage} SET calculated = 1"); + + // Remove old tracks from the system + track_remove_old_tracks(); + } catch(Exception $e) { + // Something went wrong: warn and rollback transaction. + trigger_error( + 'Page statistics calculating faild: ' . $e->getMessage(), + E_USER_WARNING + ); + $db->query('ROLLBACK'); + return; + } + + // Commit transaction + $db->query('COMMIT'); +} + ?> \ No newline at end of file