SearchController.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. <?php
  2. namespace App\Http\Controllers;
  3. use Illuminate\Http\Request;
  4. use App\Models\BookTitle;
  5. use App\Models\FtsText;
  6. use App\Models\Tag;
  7. use App\Models\TagMap;
  8. use App\Models\PaliText;
  9. use Illuminate\Support\Facades\Http;
  10. use Illuminate\Support\Facades\DB;
  11. use App\Http\Resources\SearchResource;
  12. use App\Http\Resources\SearchTitleResource;
  13. use App\Http\Resources\SearchBookResource;
  14. use Illuminate\Support\Facades\Log;
  15. use App\Tools\Tools;
  16. use App\Models\WbwTemplate;
  17. use App\Models\PageNumber;
  18. use App\Tools\PaliSearch;
  19. use Illuminate\Support\Facades\App;
  20. class SearchController extends Controller
  21. {
  22. /**
  23. * Display a listing of the resource.
  24. *
  25. * @return \Illuminate\Http\Response
  26. */
  27. public function index(Request $request)
  28. {
  29. switch ($request->input('view', 'pali')) {
  30. case 'pali':
  31. $pageHead = ['M', 'P', 'T', 'V', 'O'];
  32. $key = $request->input('key');
  33. if (substr($key, 0, 4) === 'para' || in_array(substr($key, 0, 1), $pageHead)) {
  34. return $this->page($request);
  35. } else {
  36. return $this->pali_rpc($request);
  37. }
  38. break;
  39. case 'page':
  40. return $this->page($request);
  41. break;
  42. case 'title':
  43. $key = strtolower($request->input('key'));
  44. $table = PaliText::where('level', '<', 8)
  45. ->where(function ($query) use ($key) {
  46. $query->where('title_en', 'like', "%{$key}%")
  47. ->orWhere('title', 'like', "%{$key}%");
  48. });
  49. Log::info($table->toSql());
  50. if ($request->has('tags')) {
  51. //查询搜索范围
  52. $tagItems = explode(';', $request->input('tags'));
  53. $bookId = [];
  54. foreach ($tagItems as $tagItem) {
  55. # code...
  56. $bookId = array_merge($bookId, $this->getBookIdByTags(explode(',', $tagItem)));
  57. }
  58. $table = $table->whereIn('pcd_book_id', $bookId);
  59. }
  60. $count = $table->count();
  61. $table = $table->orderBy($request->input('orderby', 'book'), $request->input('dir', 'asc'));
  62. $table = $table->skip($request->input("offset", 0))
  63. ->take($request->input('limit', 10));
  64. $result = $table->get();
  65. return $this->ok(["rows" => SearchTitleResource::collection($result), "count" => $count]);
  66. break;
  67. default:
  68. # code...
  69. break;
  70. }
  71. }
  72. public function pali(Request $request)
  73. {
  74. //
  75. $bookId = [];
  76. if ($request->has('book')) {
  77. $bookId = [(int)$request->input('book')];
  78. } else if ($request->has('tags')) {
  79. //查询搜索范围
  80. //查询搜索范围
  81. $tagItems = explode(';', $request->input('tags'));
  82. foreach ($tagItems as $tagItem) {
  83. $bookId = array_merge($bookId, $this->getBookIdByTags(explode(',', $tagItem)));
  84. }
  85. }
  86. $searchChapters = [];
  87. $searchBooks = [];
  88. $searchBookId = [];
  89. $queryBookId = '';
  90. if (count($bookId) > 0) {
  91. $queryBookId = ' AND pcd_book_id in (' . implode(',', $bookId) . ') ';
  92. }
  93. $key = explode(';', $request->input('key'));
  94. $param = [];
  95. $countParam = [];
  96. switch ($request->input('match', 'case')) {
  97. case 'complete':
  98. case 'case':
  99. # code...
  100. $querySelect_rank_base = " ts_rank('{0.1, 1, 0.3, 0.2}',
  101. full_text_search_weighted,
  102. websearch_to_tsquery('pali', ?)) ";
  103. $querySelect_rank_head = implode('+', array_fill(0, count($key), $querySelect_rank_base));
  104. $param = array_merge($param, $key);
  105. $querySelect_rank = " {$querySelect_rank_head} AS rank, ";
  106. $querySelect_highlight = " ts_headline('pali', content,
  107. websearch_to_tsquery('pali', ?),
  108. 'StartSel = ~~, StopSel = ~~,MaxWords=3500, MinWords=3500,HighlightAll=TRUE')
  109. AS highlight,";
  110. array_push($param, implode(' ', $key));
  111. break;
  112. case 'similar':
  113. # 形似,去掉变音符号
  114. $key = Tools::getWordEn($key[0]);
  115. $querySelect_rank = "
  116. ts_rank('{0.1, 1, 0.3, 0.2}',
  117. full_text_search_weighted_unaccent,
  118. websearch_to_tsquery('pali_unaccent', ?))
  119. AS rank, ";
  120. $param[] = $key;
  121. $querySelect_highlight = " ts_headline('pali_unaccent', content,
  122. websearch_to_tsquery('pali_unaccent', ?),
  123. 'StartSel = ~~, StopSel = ~~,MaxWords=3500, MinWords=3500,HighlightAll=TRUE')
  124. AS highlight,";
  125. $param[] = $key;
  126. break;
  127. }
  128. $_queryWhere = $this->getQueryWhere($request->input('key'), $request->input('match', 'case'));
  129. $queryWhere = $_queryWhere['query'];
  130. $param = array_merge($param, $_queryWhere['param']);
  131. $querySelect_2 = " book,paragraph,content ";
  132. $queryCount = "SELECT count(*) as co FROM fts_texts WHERE {$queryWhere} {$queryBookId};";
  133. $resultCount = DB::select($queryCount, $_queryWhere['param']);
  134. $limit = $request->input('limit', 10);
  135. $offset = $request->input('offset', 0);
  136. switch ($request->input('orderby', "rank")) {
  137. case 'rank':
  138. $orderby = " ORDER BY rank DESC ";
  139. break;
  140. case 'paragraph':
  141. $orderby = " ORDER BY book,paragraph ";
  142. break;
  143. default:
  144. $orderby = "";
  145. break;
  146. };
  147. $query = "SELECT
  148. {$querySelect_rank}
  149. {$querySelect_highlight}
  150. {$querySelect_2}
  151. FROM fts_texts
  152. WHERE
  153. {$queryWhere}
  154. {$queryBookId}
  155. {$orderby}
  156. LIMIT ? OFFSET ? ;";
  157. $param[] = $limit;
  158. $param[] = $offset;
  159. $result = DB::select($query, $param);
  160. return $this->ok(["rows" => SearchResource::collection($result), "count" => $resultCount[0]->co]);
  161. }
  162. public function pali_rpc(Request $request)
  163. {
  164. //
  165. $bookId = [];
  166. if ($request->has('book')) {
  167. $bookId = [(int)$request->input('book')];
  168. } else if ($request->has('tags')) {
  169. //查询搜索范围
  170. //查询搜索范围
  171. $tagItems = explode(';', $request->input('tags'));
  172. foreach ($tagItems as $tagItem) {
  173. $bookId = array_merge($bookId, $this->getBookIdByTags(explode(',', $tagItem)));
  174. }
  175. }
  176. $key = explode(';', $request->input('key'));
  177. $limit = $request->input('limit', 10);
  178. $offset = $request->input('offset', 0);
  179. $matchMode = $request->input('match', 'case');
  180. $result = PaliSearch::search($key, $bookId, $matchMode, $offset, $limit);
  181. return $this->ok(["rows" => SearchResource::collection(collect($result['rows'])), "count" => $result['total']]);
  182. }
  183. public function page(Request $request)
  184. {
  185. //
  186. $searchChapters = [];
  187. $searchBooks = [];
  188. $searchBookId = [];
  189. $queryBookId = '';
  190. $bookId = [];
  191. if ($request->has('book')) {
  192. $bookId[] = $request->input('book');
  193. } else if ($request->has('tags')) {
  194. //查询搜索范围
  195. //查询搜索范围
  196. $tagItems = explode(';', $request->input('tags'));
  197. foreach ($tagItems as $tagItem) {
  198. # code...
  199. $bookId = array_merge($bookId, $this->getBookIdByTags(explode(',', $tagItem)));
  200. }
  201. }
  202. $key = $request->input('key');
  203. $searchKey = '';
  204. $page = explode('.', $key);
  205. if (count($page) === 2) {
  206. $table = PageNumber::where('type', $request->input('type'))
  207. ->where('volume', (int)$page[0])
  208. ->where('page', (int)$page[1]);
  209. } else {
  210. if (is_numeric($key)) {
  211. $table = PageNumber::where('type', $request->input('type'))->where('page', $key);
  212. } else {
  213. $table = PageNumber::where('type', $request->input('type'))->where('page', (int)$key);
  214. }
  215. }
  216. if (count($bookId) > 0) {
  217. $table = $table->whereIn('pcd_book_id', $bookId);
  218. }
  219. $count = $table->count();
  220. $table = $table->select(['book', 'paragraph']);
  221. $table->skip($request->input("offset", 0))->take($request->input('limit', 10));
  222. $result = $table->get();
  223. return $this->ok(["rows" => SearchResource::collection($result), "count" => $count]);
  224. }
  225. public function book_list(Request $request)
  226. {
  227. $searchChapters = [];
  228. $searchBooks = [];
  229. $queryBookId = '';
  230. $bookId = [];
  231. if ($request->has('tags')) {
  232. //查询搜索范围
  233. $tagItems = explode(';', $request->input('tags'));
  234. foreach ($tagItems as $tagItem) {
  235. # code...
  236. $bookId = array_merge($bookId, $this->getBookIdByTags(explode(',', $tagItem)));
  237. }
  238. $queryBookId = ' AND pcd_book_id in (' . implode(',', $bookId) . ') ';
  239. }
  240. $key = $request->input('key');
  241. switch ($request->input('view', 'pali')) {
  242. case 'pali':
  243. # code...
  244. $pageHead = ['M', 'P', 'T', 'V', 'O'];
  245. if (substr($key, 0, 4) === 'para' || in_array(substr($key, 0, 1), $pageHead)) {
  246. $queryWhere = "type='.ctl.' AND word = ?";
  247. $query = "SELECT pcd_book_id, count(*) as co FROM wbw_templates WHERE {$queryWhere} {$queryBookId} GROUP BY pcd_book_id ORDER BY co DESC;";
  248. $result = DB::select($query, [$key]);
  249. } else {
  250. $rpc_result = PaliSearch::book_list(
  251. explode(';', $key),
  252. $bookId,
  253. $request->input('match', 'case')
  254. );
  255. $result = collect($rpc_result['rows']);
  256. /*
  257. $queryWhere = $this->getQueryWhere($key,$request->input('match','case'));
  258. $query = "SELECT pcd_book_id, count(*) as co FROM fts_texts WHERE {$queryWhere['query']} {$queryBookId} GROUP BY pcd_book_id ORDER BY co DESC;";
  259. $result = DB::select($query, $queryWhere['param']);
  260. */
  261. }
  262. break;
  263. case 'page':
  264. $type = $request->input('type', 'P');
  265. $word = "{$type}%0{$key}";
  266. $queryWhere = "type='.ctl.' AND word like ?";
  267. $query = "SELECT pcd_book_id, count(*) as co FROM wbw_templates WHERE {$queryWhere} {$queryBookId} GROUP BY pcd_book_id ORDER BY co DESC;";
  268. $result = DB::select($query, [$word]);
  269. break;
  270. case 'title':
  271. $keyLike = '%' . $key . '%';
  272. $queryWhere = "\"level\" < 8 and (\"title_en\"::text like ? or \"title\"::text like ?)";
  273. $query = "SELECT pcd_book_id, count(*) as co FROM pali_texts WHERE {$queryWhere} {$queryBookId} GROUP BY pcd_book_id ORDER BY co DESC;";
  274. $result = DB::select($query, [$keyLike, $keyLike]);
  275. break;
  276. default:
  277. # code...
  278. return $this->error('unknown view');
  279. break;
  280. }
  281. if ($result) {
  282. return $this->ok(["rows" => SearchBookResource::collection($result), "count" => count($result)]);
  283. } else {
  284. return $this->ok(["rows" => [], "count" => 0]);
  285. }
  286. }
  287. private function getQueryWhere($key, $match)
  288. {
  289. $key = explode(';', $key);
  290. $param = [];
  291. $queryWhere = '';
  292. switch ($match) {
  293. case 'complete':
  294. case 'case':
  295. # code...
  296. $queryWhereBase = " full_text_search_weighted @@ websearch_to_tsquery('pali', ?) ";
  297. $queryWhereBody = implode(' or ', array_fill(0, count($key), $queryWhereBase));
  298. $queryWhere = " ({$queryWhereBody}) ";
  299. $param = array_merge($param, $key);
  300. break;
  301. case 'similar':
  302. # 形似,去掉变音符号
  303. $queryWhere = " full_text_search_weighted_unaccent @@ websearch_to_tsquery('pali_unaccent', ?) ";
  304. $key = Tools::getWordEn($key[0]);
  305. $param = [$key];
  306. break;
  307. };
  308. return (['query' => $queryWhere, 'param' => $param]);
  309. }
  310. public function getBookIdByTags($tags)
  311. {
  312. $searchBookId = [];
  313. if (empty($tags)) {
  314. return $searchBookId;
  315. }
  316. //查询搜索范围
  317. $tagIds = Tag::whereIn('name', $tags)->select('id')->get();
  318. $paliTextIds = TagMap::where('table_name', 'pali_texts')->whereIn('tag_id', $tagIds)->select('anchor_id')->get();
  319. $paliPara = [];
  320. foreach ($paliTextIds as $key => $value) {
  321. # code...
  322. if (isset($paliPara[$value->anchor_id])) {
  323. $paliPara[$value->anchor_id]++;
  324. } else {
  325. $paliPara[$value->anchor_id] = 1;
  326. }
  327. }
  328. $paliId = [];
  329. foreach ($paliPara as $key => $value) {
  330. # code...
  331. if ($value === count($tags)) {
  332. $paliId[] = $key;
  333. }
  334. }
  335. $para = PaliText::where('level', 1)->whereIn('uid', $paliId)->get();
  336. if (count($para) > 0) {
  337. foreach ($para as $key => $value) {
  338. # code...
  339. $book_id = BookTitle::where('book', $value['book'])
  340. ->where('paragraph', $value['paragraph'])
  341. ->value('sn');
  342. if (!empty($book_id)) {
  343. $searchBookId[] = $book_id;
  344. }
  345. }
  346. }
  347. return $searchBookId;
  348. }
  349. /**
  350. * Store a newly created resource in storage.
  351. *
  352. * @param \Illuminate\Http\Request $request
  353. * @return \Illuminate\Http\Response
  354. */
  355. public function store(Request $request)
  356. {
  357. //
  358. }
  359. /**
  360. * Display the specified resource.
  361. *
  362. * @param int $id
  363. * @return \Illuminate\Http\Response
  364. */
  365. public function show($id)
  366. {
  367. //
  368. }
  369. /**
  370. * Update the specified resource in storage.
  371. *
  372. * @param \Illuminate\Http\Request $request
  373. * @param int $id
  374. * @return \Illuminate\Http\Response
  375. */
  376. public function update(Request $request, $id)
  377. {
  378. //
  379. }
  380. /**
  381. * Remove the specified resource from storage.
  382. *
  383. * @param int $id
  384. * @return \Illuminate\Http\Response
  385. */
  386. public function destroy($id)
  387. {
  388. //
  389. }
  390. }