2
0

SearchPlusController.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. <?php
  2. namespace App\Http\Controllers;
  3. use App\DTO\Search\HitItemDTO;
  4. use App\Services\OpenSearchService;
  5. use Illuminate\Http\JsonResponse;
  6. use Illuminate\Http\Request;
  7. use Illuminate\Http\Response;
  8. class SearchPlusController extends Controller
  9. {
  10. /**
  11. * 构造函数,注入 OpenSearchService
  12. */
  13. public function __construct(protected OpenSearchService $searchService) {}
  14. /**
  15. * Display a listing of the resource.
  16. *
  17. * 处理搜索请求,支持 fuzzy / exact / semantic / hybrid 四种模式。
  18. * 接收查询参数并调用 OpenSearchService 执行搜索。
  19. *
  20. * 支持 GET 和 POST 请求
  21. *
  22. * @param Request $request
  23. * - q (string): 搜索关键词
  24. * - resource_type (string): 资源类型 (article|term|dictionary|translation|origin_text|nissaya)
  25. * - granularity (string): 文档颗粒度 (book|chapter|sutta|section|paragraph|sentence)
  26. * - language (string): 语言,如 pali, zh-Hans, zh-Hant, en-US, my
  27. * - category (string): 文档分类 (pali|commentary|subcommentary)
  28. * - tags (array): 标签过滤
  29. * - page_refs (array): 页码标记 ["V3.81","M3.58"]
  30. * - related_id (array): 关联 ID,如 ["chapter_93-5","m.n. 38"]
  31. * - author (string): 作者或译者 (metadata.author)
  32. * - channel (string): 来源渠道 (metadata.channel)
  33. * - page (int): 页码,默认 1
  34. * - page_size (int): 每页数量,默认 20,最大 100
  35. * - search_mode (string): fuzzy|exact|semantic|hybrid,默认 fuzzy
  36. * @return JsonResponse
  37. */
  38. public function index(Request $request)
  39. {
  40. // 获取所有输入参数(自动兼容 GET 和 POST)
  41. $input = $request->all();
  42. // 基础参数 - 使用 $input 或直接用 $request->input() (已兼容 GET/POST)
  43. $query = $request->input('q', '');
  44. $page = max(1, (int) $request->input('page', 1));
  45. $pageSize = min(100, (int) $request->input('page_size', 20));
  46. $searchMode = $request->input('search_mode', 'fuzzy');
  47. $resourceType = $request->input('resource_type'); // 资源类型
  48. $resourceId = $request->input('resource_id'); // 资源类型
  49. $granularity = $request->input('granularity'); // 文档颗粒度
  50. $language = $request->input('language'); // 语言
  51. $category = $request->has('category') ? explode(',', $request->input('category')) : null; // 分类
  52. $tags = $request->has('tags') ? explode(',', $request->input('tags')) : []; // 标签
  53. $pageRefs = $request->input('page_refs', []); // 页码标记
  54. $relatedId = $request->input('related_id'); // 关联 ID
  55. $author = $request->input('author'); // 作者/译者 (metadata.author)
  56. $channel = $request->input('channel'); // 来源渠道 (metadata.channel)
  57. // 确保数组类型参数正确解析(POST 时可能是 JSON 字符串)
  58. $tags = is_array($tags) ? $tags : (is_string($tags) ? json_decode($tags, true) ?? [] : []);
  59. $pageRefs = is_array($pageRefs) ? $pageRefs : (is_string($pageRefs) ? json_decode($pageRefs, true) ?? [] : []);
  60. // 组装搜索参数
  61. $params = [
  62. 'query' => $query,
  63. 'page' => $page,
  64. 'pageSize' => $pageSize,
  65. 'searchMode' => $searchMode,
  66. 'resourceType' => $resourceType,
  67. 'resourceId' => $resourceId,
  68. 'granularity' => $granularity,
  69. 'language' => $language,
  70. 'category' => $category,
  71. 'tags' => $tags,
  72. 'pageRefs' => $pageRefs,
  73. 'relatedId' => $relatedId,
  74. 'author' => $author,
  75. 'channel' => $channel,
  76. ];
  77. try {
  78. // 调用 OpenSearchService 执行搜索
  79. $result = $this->searchService->search($params);
  80. return response()->json([
  81. 'success' => true,
  82. 'data' => $result,
  83. 'query_info' => [
  84. 'original_query' => $query,
  85. 'search_mode' => $searchMode,
  86. 'request_method' => $request->method(), // 可选:返回请求方法
  87. ],
  88. ]);
  89. } catch (\Exception $e) {
  90. return response()->json([
  91. 'success' => false,
  92. 'error' => $e->getMessage(),
  93. ], 500);
  94. }
  95. }
  96. /**
  97. * Store a newly created resource in storage.
  98. *
  99. * POST 方式调用搜索接口(与 index 方法功能相同)
  100. *
  101. * @route POST /api/search
  102. *
  103. * @param JSON: 搜索参数(与 index 方法参数相同)
  104. * @return JsonResponse
  105. */
  106. public function store(Request $request)
  107. {
  108. // 直接调用 index 方法,复用搜索逻辑
  109. return $this->index($request);
  110. }
  111. /**
  112. * Display the specified resource.
  113. *
  114. * @param int $id
  115. * @return Response
  116. */
  117. public function show($id)
  118. {
  119. //
  120. try {
  121. return $this->ok(HitItemDTO::fromArray($this->searchService->get($id)));
  122. } catch (\Throwable $th) {
  123. return $this->error("no such index {$id}", 404, 404);
  124. }
  125. }
  126. /**
  127. * 更新资源
  128. *
  129. * @route PUT /api/search/{uid}
  130. *
  131. * @param JSON: OpenSearch 格式数据
  132. * @return Response
  133. */
  134. public function update(Request $request, $uid) {}
  135. /**
  136. * Remove the specified resource from storage.
  137. *
  138. * 删除资源
  139. *
  140. * @route DELETE /api/search/{uid}
  141. *
  142. * @return Response
  143. */
  144. public function destroy($uid) {}
  145. }