2
0

server.php 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. <?php
  2. require_once dirname(__FILE__) . '/vendor/autoload.php';
  3. require_once dirname(__FILE__) . '/config.php';
  4. require_once dirname(__FILE__) . '/logger.php';
  5. require_once dirname(__FILE__) . '/pdo.php';
  6. use Monolog\Logger;
  7. use Monolog\Handler\StreamHandler;
  8. class Greeter extends \Mint\Tulip\V1\SearchStub
  9. {
  10. private $log = null;
  11. public function __construct()
  12. {
  13. // create a log channel
  14. $this->log = new Logger('tulip');
  15. $this->log->pushHandler(new StreamHandler(__DIR__ . '/logs/tulip-' . date("Y-m-d") . '.log'));
  16. }
  17. public function Pali(
  18. \Mint\Tulip\V1\SearchRequest $request,
  19. \Grpc\ServerContext $context
  20. ): ?\Mint\Tulip\V1\SearchResponse {
  21. $keyWords = [];
  22. foreach ($request->getKeywords()->getIterator() as $word) {
  23. $keyWords[] = $word;
  24. }
  25. $msg = "[" . date("Y/m/d h:i:sa") . "] pali search: request words = " . implode(',', $keyWords);
  26. echo $msg . PHP_EOL;
  27. $this->log->info($msg);
  28. $pdo = new PdoHelper;
  29. $pdo->connectDb();
  30. /**
  31. * 查询业务逻辑
  32. */
  33. $bookId = [];
  34. if ($request->getBooks()->count() > 0) {
  35. foreach ($request->getBooks()->getIterator() as $book) {
  36. $bookId[] = $book;
  37. }
  38. $queryBookId = ' AND pcd_book_id in (' . implode(',', $bookId) . ') ';
  39. } else {
  40. $queryBookId = '';
  41. }
  42. $msg = 'query books = ' . implode(',', $bookId);
  43. echo $msg . PHP_EOL;
  44. $this->log->info($msg);
  45. $matchMode = $request->getMatchMode();
  46. echo 'query mode = ' . $matchMode . PHP_EOL;
  47. $param = [];
  48. switch ($matchMode) {
  49. case 'complete':
  50. case 'case':
  51. # code...
  52. $querySelect_rank_base = " ts_rank('{0.1, 1, 0.3, 0.2}',
  53. full_text_search_weighted,
  54. websearch_to_tsquery('pali', ?)) ";
  55. $querySelect_rank_head = implode(
  56. '+',
  57. array_fill(
  58. 0,
  59. count($keyWords),
  60. $querySelect_rank_base
  61. )
  62. );
  63. $param = array_merge($param, $keyWords);
  64. $querySelect_rank = " {$querySelect_rank_head} AS rank, ";
  65. $querySelect_highlight = " ts_headline('pali', content,
  66. websearch_to_tsquery('pali', ?),
  67. 'StartSel = ~~, StopSel = ~~,MaxWords=3500,
  68. MinWords=3500,HighlightAll=TRUE')
  69. AS highlight,";
  70. array_push($param, implode(' ', $keyWords));
  71. break;
  72. case 'similar':
  73. # 形似,去掉变音符号
  74. $key = $this->getWordEn($keyWords[0]);
  75. $querySelect_rank = "
  76. ts_rank('{0.1, 1, 0.3, 0.2}',
  77. full_text_search_weighted_unaccent,
  78. websearch_to_tsquery('pali_unaccent', ?))
  79. AS rank, ";
  80. $param[] = $key;
  81. $querySelect_highlight = " ts_headline('pali_unaccent', content,
  82. websearch_to_tsquery('pali_unaccent', ?),
  83. 'StartSel = ~~, StopSel = ~~,
  84. MaxWords=3500, MinWords=3500,
  85. HighlightAll=TRUE')
  86. AS highlight,";
  87. $param[] = $key;
  88. break;
  89. }
  90. $_queryWhere = $this->makeQueryWhere($keyWords, $matchMode);
  91. $queryWhere = $_queryWhere['query'];
  92. $param = array_merge($param, $_queryWhere['param']);
  93. $querySelect_2 = " book,paragraph,content ";
  94. $queryCount = "SELECT count(*) as co FROM fts_texts WHERE {$queryWhere} {$queryBookId};";
  95. $resultCount = $pdo->dbSelect($queryCount, $_queryWhere['param']);
  96. if (
  97. is_array($resultCount) &&
  98. count($resultCount) > 0 &&
  99. isset($resultCount[0]['co'])
  100. ) {
  101. $total = $resultCount[0]['co'];
  102. } else {
  103. logger('warning', 'result must be of type array' . $pdo->errorInfo());
  104. $this->log->error('result must be of type array' . $pdo->errorInfo());
  105. $total = 0;
  106. }
  107. if ($request->hasPage()) {
  108. $limit = $request->getPage()->getSize();
  109. $offset = $request->getPage()->getIndex();
  110. } else {
  111. $limit = 10;
  112. $offset = 0;
  113. }
  114. $_orderBy = 'rank';
  115. switch ($_orderBy) {
  116. case 'rank':
  117. $orderby = " ORDER BY rank DESC ";
  118. break;
  119. case 'paragraph':
  120. $orderby = " ORDER BY book,paragraph ";
  121. break;
  122. default:
  123. $orderby = "";
  124. break;
  125. };
  126. $query = "SELECT
  127. {$querySelect_rank}
  128. {$querySelect_highlight}
  129. {$querySelect_2}
  130. FROM fts_texts
  131. WHERE
  132. {$queryWhere}
  133. {$queryBookId}
  134. {$orderby}
  135. LIMIT ? OFFSET ? ;";
  136. $param[] = $limit;
  137. $param[] = $offset;
  138. $result = $pdo->dbSelect($query, $param);
  139. //返回数据
  140. $response = new \Mint\Tulip\V1\SearchResponse();
  141. $output = $response->getItems();
  142. if ($result) {
  143. foreach ($result as $row) {
  144. $item = new \Mint\Tulip\V1\SearchResponse\Item;
  145. $item->setRank($row['rank']);
  146. $item->setHighlight($row['highlight']);
  147. $item->setBook($row['book']);
  148. $item->setParagraph($row['paragraph']);
  149. $item->setContent($row['content']);
  150. $output[] = $item;
  151. }
  152. }
  153. echo "total={$total}" . PHP_EOL;
  154. $this->log->info("total={$total}");
  155. $response->setTotal($total);
  156. return $response;
  157. }
  158. /**
  159. * @param \Mint\Tulip\V1\SearchRequest $request client request
  160. * @param \Grpc\ServerContext $context server request context
  161. * @return \Mint\Tulip\V1\BookListResponse for response data, null if if error occured
  162. * initial metadata (if any) and status (if not ok) should be set to $context
  163. */
  164. public function BookList(
  165. \Mint\Tulip\V1\SearchRequest $request,
  166. \Grpc\ServerContext $context
  167. ): ?\Mint\Tulip\V1\BookListResponse {
  168. $keyWords = [];
  169. foreach ($request->getKeywords()->getIterator() as $word) {
  170. $keyWords[] = $word;
  171. }
  172. echo "book list: request words = " . implode(',', $keyWords) . PHP_EOL;
  173. /**
  174. * 查询业务逻辑
  175. */
  176. $pdo = new PdoHelper;
  177. $pdo->connectDb();
  178. $bookId = [];
  179. if ($request->getBooks()->count() > 0) {
  180. foreach ($request->getBooks()->getIterator() as $book) {
  181. $bookId[] = $book;
  182. }
  183. $queryBookId = ' AND pcd_book_id in (' . implode(',', $bookId) . ') ';
  184. } else {
  185. $queryBookId = '';
  186. }
  187. echo 'query books = ' . implode(',', $bookId) . PHP_EOL;
  188. $matchMode = $request->getMatchMode();
  189. echo 'query mode = ' . $matchMode . PHP_EOL;
  190. $queryWhere = $this->makeQueryWhere($keyWords, $matchMode);
  191. $query = "SELECT pcd_book_id, count(*) as co FROM fts_texts WHERE {$queryWhere['query']} {$queryBookId} GROUP BY pcd_book_id ORDER BY co DESC;";
  192. $result = $pdo->dbSelect($query, $queryWhere['param']);
  193. //返回数据
  194. $response = new \Mint\Tulip\V1\BookListResponse();
  195. $output = $response->getItems();
  196. if ($result) {
  197. foreach ($result as $row) {
  198. $item = new \Mint\Tulip\V1\BookListResponse\Item;
  199. $item->setBook($row['pcd_book_id']);
  200. $item->setCount($row['co']);
  201. $output[] = $item;
  202. }
  203. }
  204. echo "total=" . count($output) . PHP_EOL;
  205. return $response;
  206. }
  207. private function makeQueryWhere($key, $match)
  208. {
  209. $param = [];
  210. $queryWhere = '';
  211. switch ($match) {
  212. case 'complete':
  213. case 'case':
  214. # code...
  215. $queryWhereBase = " full_text_search_weighted @@ websearch_to_tsquery('pali', ?) ";
  216. $queryWhereBody = implode(' or ', array_fill(
  217. 0,
  218. count($key),
  219. $queryWhereBase
  220. ));
  221. $queryWhere = " ({$queryWhereBody}) ";
  222. $param = array_merge($param, $key);
  223. break;
  224. case 'similar':
  225. # 形似,去掉变音符号
  226. $queryWhere = " full_text_search_weighted_unaccent @@ websearch_to_tsquery('pali_unaccent', ?) ";
  227. $key = $this->getWordEn($key[0]);
  228. $param = [$key];
  229. break;
  230. };
  231. return (['query' => $queryWhere, 'param' => $param]);
  232. }
  233. private function getWordEn($strIn)
  234. {
  235. $out = str_replace(
  236. ["ā", "ī", "ū", "ṅ", "ñ", "ṭ", "ḍ", "ṇ", "ḷ", "ṃ"],
  237. ["a", "i", "u", "n", "n", "t", "d", "n", "l", "m"],
  238. $strIn
  239. );
  240. return ($out);
  241. }
  242. }
  243. $port = Config['port'];
  244. if (!isset($port)) {
  245. echo 'parameter port is required. ';
  246. return;
  247. }
  248. $server = new \Grpc\RpcServer();
  249. $server->addHttp2Port('0.0.0.0:' . $port);
  250. $server->handle(new Greeter());
  251. echo 'Listening on port :' . $port . PHP_EOL;
  252. $server->run();