SearchController.php 15 KB

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