EsDepartment.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. <?php
  2. namespace app\controller;
  3. use app\model\CdssXyDisease;
  4. use app\model\XyZskDisease;
  5. use think\facade\Log;
  6. use think\facade\Request;
  7. use think\response\Json;
  8. /**
  9. * Es学科分析
  10. */
  11. class EsDepartment extends CommonEsController
  12. {
  13. /**
  14. * 首页
  15. *
  16. * @param string $value
  17. * @param string $year
  18. * @param string $tag
  19. * @return Json
  20. */
  21. public function index():Json
  22. {
  23. $selectValue = Request::param('value') ?? '';
  24. $year = Request::param('year') ?? '';
  25. $tag = Request::param('tag') ?? 'disease';
  26. if( ! $selectValue || ! $year) {
  27. return $this->_json_error('参数请求有误!');
  28. }
  29. /**
  30. * 单个|多个 疾病
  31. */
  32. if('disease' === $tag) {
  33. if(stripos($selectValue, ',') !== false) {
  34. $diseaseList = explode(',' , $selectValue);
  35. } else {
  36. $diseaseList = $selectValue;
  37. }
  38. }
  39. /**
  40. * 某个科室下疾病
  41. */
  42. if('department' === $tag) {
  43. $diseaseList = $this->getDiseaseByDepartment($selectValue);
  44. }
  45. /**
  46. * es查询数据
  47. */
  48. $esData = $this->esQuery($diseaseList , $year);
  49. /**
  50. * 相关的发文总量
  51. */
  52. $total = $esData['hits']['total'];
  53. /**
  54. * 主要主题统计
  55. */
  56. $subjectTop = $esData['aggregations']['subjectTop']['buckets'][0]['doc_count'] ?? 0;;
  57. /**
  58. * 次要主题统计
  59. */
  60. $subjectSub = $esData['aggregations']['subjectSub']['buckets'][0]['doc_count'] ?? 0;
  61. /**
  62. * 被引用文章数量
  63. */
  64. $citedCnt = $esData['aggregations']['citedCnt']['doc_count'];
  65. /**
  66. * 总的被引量
  67. */
  68. $totalCitationCnt = $esData['aggregations']['citedCnt']['totalCitationCnt']['value'];
  69. /**
  70. * 最高单篇被引量
  71. */
  72. $maxCitation = $esData['aggregations']['citedCnt']['maxCitation']['value'];
  73. /**
  74. * 篇平均被引量
  75. */
  76. $citationsPerArticleAverageNumber = 0 == $citedCnt ? 0 : ceil($totalCitationCnt / $citedCnt);
  77. /**
  78. * 合作成功数
  79. */
  80. $successCopOrg = $esData['aggregations']['successCopOrg']['doc_count'];
  81. /**
  82. * 合作机构数
  83. */
  84. $corOrgCnt = $esData['aggregations']['successCopOrg']['corOrgCnt']['value'];
  85. /**
  86. * 合作学者数
  87. */
  88. $corAuthorCnt = $esData['aggregations']['successCopAuthor']['corAuthorCnt']['value'];
  89. /**
  90. * 被引用的文献总作者数量
  91. */
  92. $citedAuthorCnt = $esData['aggregations']['citedCnt']['citedAuthorCnt']['value'];
  93. /**
  94. * 总的发文作者数量
  95. */
  96. $totalAuthorCnt = $esData['aggregations']['totalAuthorCnt']['value'];
  97. /**
  98. * 作者人均发文量
  99. */
  100. $authorPerArticleNum = 0 == $totalAuthorCnt ? 0 : round($total / $totalAuthorCnt , 2);
  101. /**
  102. * 作者人均被引量
  103. */
  104. $authorPerCitation = 0 == $citedAuthorCnt ? 0 : round($citedCnt / $citedAuthorCnt , 2);
  105. /**
  106. * 被引趋势
  107. */
  108. $postTrend = $esData['aggregations']['docStat']['buckets'];
  109. $citedTrend = [];
  110. foreach ($postTrend as $key => $value) {
  111. $citedTrend[$key]['key'] = $value['key'];
  112. $citedTrend[$key]['doc_count'] = $value['citedPerYear']['value'];
  113. }
  114. $relevantScholars = $esData['aggregations']['topAuthors']['buckets'];
  115. $newRelevantScholars = [];
  116. foreach($relevantScholars as $key => $value) {
  117. $arr = explode('#' , $value['key']);
  118. $newRelevantScholars[$key]['key'] = $arr[0];
  119. $newRelevantScholars[$key]['org'] = $arr[1];
  120. $newRelevantScholars[$key]['doc_count'] = $value['doc_count'];
  121. //$newRelevantScholars[$key]['org'] = $this->getOrganization($value['key']);
  122. }
  123. /**
  124. * 数据返回
  125. */
  126. $esDepartment = [
  127. /**
  128. * 查询值
  129. */
  130. 'value' => $selectValue ,
  131. /**
  132. * 数据统计
  133. */
  134. 'count' => [
  135. /**
  136. * 学术生产力
  137. */
  138. 'academic_productivity' => [
  139. 'doc_num' => $total ,
  140. 'subject_top' => $subjectTop ,
  141. 'subject_sub' => $subjectSub ,
  142. ],
  143. /**
  144. * 学术影响力
  145. */
  146. 'academic_influence' => [
  147. 'cited_amount' => $totalCitationCnt , // 被引量
  148. 'highest_single_article_citation_amount' => 0 == $total ? 0 : $maxCitation, // 最高单篇被引量
  149. 'citations_per_article_Average_number' => $citationsPerArticleAverageNumber , // 篇平均被引量
  150. 'cited_rate' => 0 == $total ? 0 : round($citedCnt / $total , 2) , // 被引率
  151. ] ,
  152. /**
  153. * 合作共创力
  154. */
  155. 'cooperation_creativity' => [
  156. 'partner_success_num' => $successCopOrg , // 合作成功数
  157. 'partner_organization_num' => $corOrgCnt , // 合作成功数
  158. 'partner_author_num' => $corAuthorCnt , // 合作成功数
  159. ] ,
  160. /**
  161. * 科研学者力
  162. */
  163. 'power_scientific_research_scholar' => [
  164. 'publish_doc_author_num' => $citedAuthorCnt, // 发文作者数
  165. 'author_per_article_num' => $authorPerArticleNum , // 作者人均发文量
  166. 'author_per_citation' => $authorPerCitation , // 作者人均被引量
  167. ]
  168. ] ,
  169. /**
  170. * 统计图
  171. */
  172. 'detail_analyse' => [
  173. 'post_trend' => $postTrend , // 发文趋势
  174. 'cited_trend' => $citedTrend , // 被引趋势
  175. 'subject_infiltration' => $esData['aggregations']['topSubject']['buckets'] , // 学科渗透
  176. 'research_topic' => $esData['aggregations']['keywordCnt']['buckets'] , // 研究主题
  177. 'hot_body' => $esData['aggregations']['topOrgs']['buckets'] , // 热门机构
  178. 'relevant_scholars' => $newRelevantScholars , // 相关学者
  179. 'subject_top' => $esData['aggregations']['subjectTop']['buckets'], // 主要主题
  180. 'subject_sub' => $esData['aggregations']['subjectSub']['buckets'], // 次要主题
  181. ]
  182. ];
  183. return $this->_json_succ(
  184. $esDepartment
  185. );
  186. }
  187. /**
  188. * 获取学者机构
  189. */
  190. protected function getOrganization($author)
  191. {
  192. $index = $this->currentLanguage();
  193. $params = [
  194. 'index' => $index ,
  195. 'body' => [
  196. 'query' => [
  197. 'bool' => [
  198. 'filter' => [
  199. 'term' => [
  200. 'author_list.keyword' => $author
  201. ]
  202. ]
  203. ]
  204. ],
  205. 'size' => 30
  206. ]
  207. ];
  208. $client = $this->getEsClient();
  209. $result = $client->search($params);
  210. $total = $result['hits']['total'];
  211. $data = $result['hits']['hits'];
  212. $org['org'] = '';
  213. if(0 == $total) {
  214. return $org;
  215. }
  216. $source = array_column($data , '_source');
  217. $authorOrgList = array_column($source , 'author_org_list');
  218. $str = [];
  219. foreach($authorOrgList as $key => $value) {
  220. if (!is_array($value)){
  221. continue;
  222. }
  223. $valueCount = count($value);
  224. for ($i=0; $i<$valueCount; $i++) {
  225. $orgAuthor = $value[$i];
  226. if(stripos($orgAuthor , $author) !== false) {
  227. $str = $orgAuthor;
  228. }
  229. }
  230. }
  231. if(empty($str)) {
  232. return $org;
  233. }
  234. $authorOrgArr = explode('#' , $str);
  235. $org = $authorOrgArr[1] ?? '';
  236. return $org;
  237. }
  238. /**
  239. * 某个科室下疾病
  240. *
  241. * @param string $department
  242. * @return array
  243. */
  244. protected function getDiseaseByDepartment($department):array
  245. {
  246. $singleDepartmentDiseases = XyZskDisease::field('name , departmentLevel1 as department')->withSearch('departmentLevel1' ,
  247. [
  248. 'departmentLevel1' => $department
  249. ]
  250. )->select()->toArray();
  251. if(empty($singleDepartmentDiseases)) {
  252. $singleDepartmentDiseases = [];
  253. }
  254. return array_column(
  255. $singleDepartmentDiseases , 'name'
  256. );
  257. }
  258. /**
  259. * es-query查询
  260. *
  261. * @param string|array $diseaseList
  262. * @param string $year
  263. * @return array
  264. */
  265. protected function esQuery($diseaseList , $year):array
  266. {
  267. $yearArr = explode(',', $year);
  268. if(is_array($diseaseList)) {
  269. foreach($diseaseList as $disease) {
  270. $should[] = [
  271. 'match_phrase' => [
  272. 'title' => $disease
  273. ]
  274. ];
  275. }
  276. } else {
  277. $disease = $diseaseList;
  278. $should[] = [
  279. 'match_phrase' => [
  280. 'title' => $disease
  281. ]
  282. ];
  283. }
  284. $params = [
  285. 'index' => $this->currentLanguage(),
  286. 'body' => [
  287. 'size' => 20 ,
  288. 'query' => [
  289. 'bool' => [
  290. 'must' => [
  291. [
  292. 'range' => [
  293. 'year' => [
  294. 'gte' => $yearArr[0] ,
  295. 'lte' => $yearArr[1]
  296. ]
  297. ]
  298. ]
  299. ] ,
  300. 'should' => [
  301. $should
  302. ] ,
  303. 'minimum_should_match' => 1
  304. ]
  305. ] ,
  306. 'aggs' => [
  307. 'topSubject' => [
  308. 'terms' => [
  309. 'field' => 'subject_top_list.keyword' ,
  310. 'order' => [
  311. '_count' => 'desc'
  312. ] ,
  313. 'size' => 10
  314. ]
  315. ] ,
  316. 'topAuthors' => [
  317. 'terms' => [
  318. 'field' => 'author_org_list.keyword' ,
  319. 'order' => [
  320. '_count' => 'desc'
  321. ] ,
  322. 'size' => 15
  323. ]
  324. ],
  325. 'topOrgs' => [
  326. 'terms' => [
  327. 'field' => 'organization_parsed.keyword' ,
  328. 'order' => [
  329. '_count' => 'desc'
  330. ] ,
  331. 'size' => 15
  332. ]
  333. ],
  334. 'keywordCnt' => [
  335. 'terms' => [
  336. 'field' => 'keyword_list.keyword' ,
  337. 'order' => [
  338. '_count' => 'desc'
  339. ] ,
  340. 'size' => 20
  341. ]
  342. ],
  343. 'docStat' => [
  344. 'terms' => [
  345. 'field' => 'year' ,
  346. 'order' => [
  347. '_key' => 'asc'
  348. ] ,
  349. 'size' => 200
  350. ] ,
  351. 'aggs' => [
  352. 'citedPerYear' => [
  353. 'sum' => [
  354. 'field' => 'citation_relate_count'
  355. ]
  356. ]
  357. ]
  358. ],
  359. 'citedCnt' => [
  360. 'filter' => [
  361. 'range' => [
  362. 'citation_relate_count' => [
  363. 'gte' => 1
  364. ]
  365. ]
  366. ] ,
  367. 'aggs' => [
  368. 'totalCitationCnt' => [
  369. 'sum' => [
  370. 'field' => 'citation_relate_count'
  371. ]
  372. ] ,
  373. 'maxCitation' => [
  374. 'max' => [
  375. 'field' => 'citation_relate_count'
  376. ]
  377. ] ,
  378. 'citedAuthorCnt' => [
  379. 'cardinality' => [
  380. 'field' => 'author_list.keyword'
  381. ]
  382. ]
  383. ]
  384. ],
  385. 'successCopOrg' => [
  386. 'filter' => [
  387. 'range' => [
  388. 'organization_count' => [
  389. 'gte' => 1
  390. ]
  391. ]
  392. ] ,
  393. 'aggs' => [
  394. 'corOrgCnt' => [
  395. 'cardinality' => [
  396. 'field' => 'organization_parsed.keyword'
  397. ]
  398. ]
  399. ]
  400. ],
  401. 'successCopAuthor' => [
  402. 'filter' => [
  403. 'range' => [
  404. 'author_count' => [
  405. 'gt' => 1
  406. ]
  407. ]
  408. ] ,
  409. 'aggs' => [
  410. 'corAuthorCnt' => [
  411. 'cardinality' => [
  412. 'field' => 'author_list.keyword'
  413. ]
  414. ]
  415. ]
  416. ],
  417. 'totalAuthorCnt' => [
  418. 'cardinality' => [
  419. 'field' => 'author_list.keyword' ,
  420. 'precision_threshold' => 1000
  421. ]
  422. ],
  423. 'subjectTop' => [
  424. 'terms' => [
  425. 'field' => 'subject_top_list.keyword' ,
  426. 'order' => [
  427. '_count' => 'desc'
  428. ],
  429. 'size' => 20
  430. ] ,
  431. ],
  432. 'subjectSub' => [
  433. 'terms' => [
  434. 'field' => 'subject_sub_list.keyword' ,
  435. 'order' => [
  436. '_count' => 'desc'
  437. ],
  438. 'size' => 20
  439. ] ,
  440. ]
  441. ] ,
  442. 'sort' => [
  443. [
  444. 'year' => [
  445. 'order' => 'desc'
  446. ]
  447. ]
  448. ]
  449. ]
  450. ];
  451. $client = $this->getEsClient();
  452. return $client->search(
  453. $params
  454. );
  455. }
  456. /**
  457. * 搜索疾病提示(本科室下搜索)
  458. *
  459. * @param string $disease 疾病名称
  460. * @return Json
  461. */
  462. public function searchDisease():Json
  463. {
  464. $department = Request::param('department') ?? '';
  465. $disease = Request::param('disease') ?? '';
  466. if( ! $disease || ! $department) {
  467. return $this->_json_error('请求参数错误!');
  468. }
  469. $diseaseList = CdssXyDisease::field('name')->where('department_1' , $department)->where('name' , 'like' , "%$disease%")->whereOr('alias' , 'like' , "%$disease%")->select()->toArray();
  470. if(empty($disease)) {
  471. $diseaseList = [];
  472. }
  473. return $this->_json_succ(
  474. $diseaseList
  475. );
  476. }
  477. /**
  478. * 全部文献(相关推荐底部)
  479. */
  480. public function allDocument()
  481. {
  482. $page = Request::param('page') ?? 1;
  483. $limit = ($page - 1) * $this->pagesize;
  484. $tag = Request::param('tag') ?? '';
  485. $values = Request::param('values') ?? '三明';
  486. if( ! $values) {
  487. return $this->_json_error('请求参数有误!');
  488. }
  489. switch($tag) {
  490. /**
  491. * 学科渗透
  492. */
  493. case "subject_infiltration":
  494. $field = 'subject_top_list.keyword';
  495. break;
  496. /**
  497. * 研究主题
  498. */
  499. case "research_topic":
  500. $field = 'subject_top_list.keyword';
  501. break;
  502. /**
  503. * 热门机构
  504. */
  505. case "hot_body":
  506. $field = 'organization_parsed.keyword';
  507. break;
  508. /**
  509. * 相关学者
  510. */
  511. case "relevant_scholars":
  512. $field = 'author_list.keyword';
  513. break;
  514. default:
  515. $field = 'title';
  516. break;
  517. }
  518. $query = [];
  519. if(stripos($values , ',') !== false) {
  520. $valuesArr = explode(',' , $values);
  521. foreach ($valuesArr as $value) {
  522. if('relevant_scholars' === $tag) {
  523. $valuesArr = explode('-', $value);
  524. $value = $valuesArr[0];
  525. }
  526. $query['bool']['must'][] = [
  527. 'match' => [
  528. $field => $value
  529. ]
  530. ];
  531. }
  532. } else {
  533. $query['bool']['must'][] = [
  534. 'match' => [
  535. $field => $values
  536. ]
  537. ];
  538. }
  539. $params = [
  540. 'index' => $this->currentLanguage() ,
  541. 'body' => [
  542. 'from' => $limit,
  543. 'size' => $this->pagesize,
  544. 'query' => $query,
  545. 'sort' => [
  546. [
  547. 'year' => [
  548. 'order' => 'desc'
  549. ]
  550. ]
  551. ]
  552. ]
  553. ];
  554. $client = $this->getEsClient();
  555. $result = $client->search(
  556. $params
  557. );
  558. $total = $result['hits']['total'];
  559. $totalPage = ceil($total / $this->pagesize);
  560. $hits = $result['hits']['hits'];
  561. $data = array_column($hits, '_source');
  562. return $this->_json_succ(
  563. [
  564. 'total_page' => $totalPage ,
  565. 'total' => $total,
  566. 'list' => $data
  567. ]
  568. );
  569. }
  570. }