Logger.php 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. #!/usr/bin/env php
  2. <?php
  3. /**
  4. * Xunsearch PHP-SDK 搜索日志管理工具
  5. *
  6. * @author hpxl
  7. * @link http://www.xunsearch.com/
  8. * @copyright Copyright &copy; 2011 HangZhou YunSheng Network Technology Co., Ltd.
  9. * @license http://www.xunsearch.com/license/
  10. * @version $Id$
  11. */
  12. require_once dirname(__FILE__) . '/../lib/XS.php';
  13. require_once dirname(__FILE__) . '/XSUtil.class.php';
  14. // check arguments
  15. XSUtil::parseOpt(array('p', 'c', 'project', 'charset', 'hot', 'del', 'put', 'query', 'import', 'limit'));
  16. $project = XSUtil::getOpt('p', 'project', true);
  17. $query = XSUtil::getOpt(null, 'query', true);
  18. // magick output charset
  19. $charset = XSUtil::getOpt('c', 'charset');
  20. XSUtil::setCharset($charset);
  21. // long options
  22. $params = array('import', 'del', 'put', 'flush', 'hot', 'clean', 'limit');
  23. foreach ($params as $_)
  24. {
  25. $k = strtr($_, '-', '_');
  26. $$k = XSUtil::getOpt(null, $_);
  27. }
  28. if ($query === null && $put === null && $del === null && $flush === null && $import === null && $hot === null
  29. && $clean === null)
  30. $hot = 'total';
  31. // help message
  32. if (XSUtil::getOpt('h', 'help') !== null || !is_string($project)
  33. || ($import !== null && !is_string($import)) || ($query !== null && !is_string($query))
  34. || ($put !== null && !is_string($put)) || ($del !== null && !is_string($del)))
  35. {
  36. $version = PACKAGE_NAME . '/' . PACKAGE_VERSION;
  37. echo <<<EOF
  38. Logger - 搜索日志管理工具 ($version)
  39. 用法
  40. {$_SERVER['argv'][0]} [options] [-p|--project] [project] [[--query] <word>]
  41. 选项说明
  42. --project=<name|ini>
  43. -p <project> 用于指定要搜索的项目名称或项目配置文件的路径,
  44. 如果指定的是名称,则使用 ../app/<name>.ini 作为配置文件
  45. --charset=<gbk|utf-8>
  46. -c <charset> 指定您当前在用以及导入数据源的字符集,以便系统进行
  47. 智能转换(默认:UTF-8)
  48. --import=<file> 导入搜索日志文件, 一行一个词, 每行的数据中
  49. 可以用\\t(Tab键)分开指定次数,没有次数默认为1
  50. --put=<word1[:wdf1][,word2[:wdf2]]>
  51. 添加搜索日志词汇,词与次数之间用半角冒号分隔,
  52. 默认为 1 次。多个词之间用半角的逗号分隔,
  53. 词之间如果包含空格,请将参数用引号包围起来。
  54. --del=<word1[,word2[,word3]]>
  55. 删除搜索日志中的词汇记录,若不存在则会给出提示,
  56. 多个词之间用半角的逗号分隔,如果包含空格,请将参数用引号包围起来。
  57. --flush 刷新搜索日志变动,如急着看效果,请调用该选项强制刷新所有提交。
  58. --clean 清空全部搜索日志内容
  59. --limit=<num> 用于控制 query 和 hot 选项的返回关键词个数
  60. --query=<word> 以 word 为关键词查找相关搜索词,用 limit 选项设置个数,默认 6 个
  61. --hot=<total|last|cur>
  62. 列出热门搜索词汇,可结合 limit 指定个数,默认 10 个
  63. 参数依次表示总次数、上期次数、本期次数
  64. -h|--help 显示帮助信息
  65. EOF;
  66. exit(0);
  67. }
  68. // create xs project
  69. $ini = file_exists($project) ? $project : dirname(__FILE__) . '/../app/' . $project . '.ini';
  70. if (!file_exists($ini))
  71. {
  72. echo "错误:无效的项目名称 ($project),不存在相应的配置文件。\n";
  73. exit(-1);
  74. }
  75. try
  76. {
  77. $db = XSSearch::LOG_DB;
  78. $log_ready = false;
  79. $xs = new XS($ini);
  80. $xs->setScheme(XSFieldScheme::logger());
  81. $search = $xs->search;
  82. try
  83. {
  84. // NOTE: use setQuery to call preQueryString for preparing fieldset
  85. $search->setDb($db)->setQuery('dummy');
  86. $log_ready = true;
  87. }
  88. catch (Exception $e)
  89. {
  90. }
  91. // hot, query ==> read-only
  92. if ($hot !== null)
  93. {
  94. $limit = $limit === null ? 10 : intval($limit);
  95. $type = $hot === 'cur' ? 'currnum' : ($hot === 'last' ? 'lastnum' : 'total');
  96. $result = $search->getHotQuery($limit, $type);
  97. if (count($result) === 0)
  98. echo "暂无相关热门搜索记录。\n";
  99. else
  100. {
  101. $i = 1;
  102. printf("序 %s %s\n%s\n", XSUtil::fixWidth('搜索热门关键词(' . $type . ')', 40), XSUtil::fixWidth('次数', 10), XSUtil::fixWidth('', 56, '-'));
  103. foreach ($result as $word => $freq)
  104. {
  105. printf("%2d. %s %d\n", $i, XSUtil::fixWidth($word, 40), $freq);
  106. $i++;
  107. }
  108. }
  109. }
  110. else if ($query !== null)
  111. {
  112. $query = XSUtil::convertIn($query);
  113. $limit = $limit === null ? 6 : intval($limit);
  114. $result = $log_ready ? $search->setFuzzy()->setLimit($limit)->search($query) : array();
  115. if (count($result) === 0)
  116. echo "目前还没有与 \033[7m" . $query . "\033[m 相关的搜索词。\n";
  117. else
  118. {
  119. printf("序 %s %s\n%s\n", XSUtil::fixWidth("相关搜索词($query)", 41), XSUtil::fixWidth('次数', 10), XSUtil::fixWidth('', 50, '-'));
  120. for ($i = 0, $total = count($result); $i < $total; $i++)
  121. {
  122. printf("%2d. %s %s\n", $i + 1, XSUtil::fixWidth($result[$i]->body, 40), $result[$i]->total);
  123. }
  124. }
  125. }
  126. else
  127. {
  128. // check clean
  129. if ($clean !== null)
  130. {
  131. echo "清空已有搜索日志数据 ...\n";
  132. $xs->index->setDb($db)->clean();
  133. }
  134. // import from file
  135. if ($import !== null)
  136. {
  137. if (!file_exists($import) || !($fd = @fopen($import, "r")))
  138. echo "要导入的文件 [$import] 不存在或无法读取!\n";
  139. else
  140. {
  141. echo "开始导入搜索日志文件 ...\n";
  142. while (($line = fgets($fd, 1024)) !== false)
  143. {
  144. if ($line[0] === '#' || $line[0] === ';')
  145. continue;
  146. if (($pos = strpos($line, "\t")) !== false)
  147. {
  148. $word = trim(substr($line, 0, $pos));
  149. $wdf = intval(substr($line, $pos + 1));
  150. }
  151. else
  152. {
  153. $word = trim($line);
  154. $wdf = 1;
  155. }
  156. add_search_log($word, $wdf);
  157. }
  158. fclose($fd);
  159. }
  160. }
  161. // delete word
  162. if ($del !== null)
  163. {
  164. $limit = $limit === null ? 3 : intval($limit);
  165. $del = XSUtil::convertIn($del);
  166. foreach (explode(",", $del) as $word)
  167. {
  168. $word = trim($word);
  169. if ($word === '')
  170. continue;
  171. if ($log_ready)
  172. {
  173. $search->setQuery(null)->addQueryTerm('id', $word);
  174. if ($search->count() === 1)
  175. {
  176. $xs->index->setDb($db)->del($word);
  177. echo "成功删除 \033[7m$word\033[m!\n";
  178. continue;
  179. }
  180. }
  181. echo "不存在 \033[7m$word\033[m,";
  182. $docs = $log_ready ? $search->setFuzzy()->setLimit($limit)->search($word) : array();
  183. if (count($docs) === 0)
  184. echo "并且没有相关的搜索词。";
  185. else
  186. {
  187. echo "相关词:";
  188. foreach ($docs as $doc)
  189. {
  190. echo "\033[7m" . $doc->body . "\033[m ";
  191. }
  192. }
  193. echo "\n";
  194. }
  195. }
  196. else if ($put !== null)
  197. {
  198. echo "开始增加/更新搜索词 ... \n";
  199. $put = XSUtil::convertIn($put);
  200. foreach (explode(',', $put) as $tmp)
  201. {
  202. if (($pos = strpos($tmp, ':')) !== false)
  203. {
  204. $word = trim(substr($tmp, 0, $pos));
  205. $wdf = intval(substr($tmp, $pos + 1));
  206. }
  207. else
  208. {
  209. $word = trim($tmp);
  210. $wdf = 1;
  211. }
  212. add_search_log($word, $wdf);
  213. }
  214. }
  215. // check flush
  216. if ($flush !== null || $del !== null)
  217. {
  218. echo "刷新已提交的日志索引 ...";
  219. $res = $xs->index->setDb($db)->flushIndex();
  220. for ($i = 0; $i < 3 && $flush !== null; $i++)
  221. {
  222. echo ".";
  223. XSUtil::flush();
  224. sleep(1);
  225. }
  226. echo $res ? " 成功\n" : " 失败\n";
  227. }
  228. if ($flush !== null || $import !== null || $put !== null)
  229. {
  230. echo "强制刷新未处理的日志记录 ... ";
  231. echo $xs->index->flushLogging() ? "成功" : "失败";
  232. echo "\n注意:后台更新需要一些时间,并不是实时完成!\n";
  233. }
  234. }
  235. }
  236. catch (XSException $e)
  237. {
  238. // Exception
  239. $start = dirname(dirname(__FILE__));
  240. $relative = XSException::getRelPath($start);
  241. $traceString = $e->getTraceAsString();
  242. $traceString = str_replace(dirname(__FILE__) . '/', '', $traceString);
  243. $traceString = str_replace($start . ($relative === '' ? '/' : ''), $relative, $traceString);
  244. echo $e . "\n" . $traceString . "\n";
  245. }
  246. // local function add word
  247. function add_search_log($word, $wdf)
  248. {
  249. global $search, $log_ready;
  250. static $record = array();
  251. if ($word !== '' && $wdf > 0)
  252. {
  253. if (!isset($record[$word]) && $log_ready)
  254. {
  255. $docs = $search->setQuery(null)->addQueryTerm('id', $word)->search();
  256. if (isset($docs[0]))
  257. $record[$word] = $docs[0]->total;
  258. }
  259. if (isset($record[$word]))
  260. {
  261. echo "更新 \033[7m$word\033[m 的次数:" . $record[$word] . " + " . $wdf . "\n";
  262. $record[$word] += $wdf;
  263. }
  264. else
  265. {
  266. echo "新增 \033[7m$word\033[m 次数:$wdf\n";
  267. $record[$word] = $wdf;
  268. }
  269. $search->addSearchLog($word, $wdf);
  270. }
  271. }