ElasticsearchBuilder.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. <?php
  2. namespace App\Search\Builders;
  3. use Closure;
  4. use Laravel\Scout\Builder;
  5. class ElasticsearchBuilder extends Builder
  6. {
  7. /**
  8. * @param string|Closure $field
  9. * @param mixed $value
  10. * @return $this
  11. */
  12. public function where($field, $value = null)
  13. {
  14. if ($field instanceof Closure) {
  15. $shouldBuilder=new SubBuilder();
  16. call_user_func($field, $shouldBuilder);
  17. $this->wheres['must']['query'][]=$shouldBuilder->getQueryData();
  18. return $this;
  19. }
  20. $this->wheres['must']['where'][]=[
  21. 'field'=>$field,
  22. 'value'=>$value
  23. ];
  24. return $this;
  25. }
  26. /**
  27. * @param string|Closure $field
  28. * @param string|int $value
  29. * @return $this
  30. */
  31. public function whereNot($field, $value = null)
  32. {
  33. if ($field instanceof Closure) {
  34. $shouldBuilder=new SubBuilder();
  35. call_user_func($field, $shouldBuilder);
  36. $this->wheres['must_not']['query'][]=$shouldBuilder->getQueryData();
  37. return $this;
  38. }
  39. $this->wheres['must_not']['where'][]=[
  40. 'field'=>$field,
  41. 'value'=>$value
  42. ];
  43. return $this;
  44. }
  45. /**
  46. * @param string|Closure $field
  47. * @param string|int $value
  48. * @return $this
  49. */
  50. public function whereOr($field, $value = null)
  51. {
  52. if ($field instanceof Closure) {
  53. $shouldBuilder=new SubBuilder();
  54. call_user_func($field, $shouldBuilder);
  55. $this->wheres['should']['query'][]=$shouldBuilder->getQueryData();
  56. return $this;
  57. }
  58. $this->wheres['should']['where'][]=[
  59. 'field'=>$field,
  60. 'value'=>$value
  61. ];
  62. return $this;
  63. }
  64. /**
  65. * @param string $field
  66. * @param array $value
  67. * @param bool $isKeyword
  68. * @return $this
  69. */
  70. public function whereIn(string $field, array $value, $isKeyword = true)
  71. {
  72. if ($isKeyword) {
  73. $this->wheres['in']['terms'][]=[
  74. 'field'=>$field,
  75. 'value'=>$value
  76. ];
  77. } else {
  78. $this->wheres['in']['phrase'][]=[
  79. 'field'=>$field,
  80. 'value'=>$value
  81. ];
  82. }
  83. return $this;
  84. }
  85. /**
  86. * @param string $field
  87. * @param array $value
  88. * @param bool $isKeyword
  89. * @return $this
  90. */
  91. public function whereOrIn(string $field, array $value, $isKeyword = true)
  92. {
  93. if ($isKeyword) {
  94. $this->wheres['should_in']['terms'][]=[
  95. 'field'=>$field,
  96. 'value'=>$value
  97. ];
  98. } else {
  99. $this->wheres['should_in']['phrase'][]=[
  100. 'field'=>$field,
  101. 'value'=>$value
  102. ];
  103. }
  104. return $this;
  105. }
  106. /**
  107. * @param string $field
  108. * @param array $value
  109. * @param bool $isKeyword
  110. * @return $this
  111. */
  112. public function whereNotIn(string $field, array $value, $isKeyword = true)
  113. {
  114. if ($isKeyword) {
  115. $this->wheres['not_in']['terms'][]=[
  116. 'field'=>$field,
  117. 'value'=>$value
  118. ];
  119. } else {
  120. $this->wheres['not_in']['phrase'][]=[
  121. 'field'=>$field,
  122. 'value'=>$value
  123. ];
  124. }
  125. return $this;
  126. }
  127. /**
  128. * @param string $field
  129. * @param null $min
  130. * @param null $max
  131. * @param bool $equal
  132. * @return $this
  133. */
  134. public function whereRange(string $field, $min = null, $max = null, $equal = true)
  135. {
  136. $equal=$equal?'e':'';
  137. $range=[];
  138. if (!is_null($min)) {
  139. $range['gt'.$equal]=$min;
  140. }
  141. if (!is_null($max)) {
  142. $range['lt'.$equal]=$max;
  143. }
  144. $this->wheres['must']['range'][]=[
  145. 'field'=>$field,
  146. 'value'=>$range
  147. ];
  148. return $this;
  149. }
  150. /**
  151. * @param string $field
  152. * @param null $min
  153. * @param null $max
  154. * @param bool $equal
  155. * @return $this
  156. */
  157. public function whereOrRange(string $field, $min = null, $max = null, $equal = true)
  158. {
  159. $equal=$equal?'e':'';
  160. $range=[];
  161. if (!is_null($min)) {
  162. $range['gt'.$equal]=$min;
  163. }
  164. if (!is_null($max)) {
  165. $range['lt'.$equal]=$max;
  166. }
  167. $this->wheres['should']['range'][]=[
  168. 'field'=>$field,
  169. 'value'=>$range
  170. ];
  171. return $this;
  172. }
  173. /**
  174. * @param string $field
  175. * @param null $min
  176. * @param null $max
  177. * @param bool $equal
  178. * @return $this
  179. */
  180. public function whereNotRange(string $field, $min = null, $max = null, $equal = true)
  181. {
  182. $equal=$equal?'e':'';
  183. $range=[];
  184. if (!is_null($min)) {
  185. $range['gt'.$equal]=$min;
  186. }
  187. if (!is_null($max)) {
  188. $range['lt'.$equal]=$max;
  189. }
  190. $this->wheres['must_not']['range'][]=[
  191. 'field'=>$field,
  192. 'value'=>$range
  193. ];
  194. return $this;
  195. }
  196. /**
  197. * @param string $field
  198. * @param $lat
  199. * @param $lon
  200. * @param $distance
  201. * @return $this
  202. */
  203. public function whereLocation(string $field, $lat, $lon, $distance)
  204. {
  205. $this->wheres['locations'][]=['distance'=>$distance, $field=>['lat'=>$lat, "lon"=>$lon]];
  206. return $this;
  207. }
  208. public function getQueryData()
  209. {
  210. $query = [];
  211. $must_data = [];
  212. $must_not_data = [];
  213. $should_data = [];
  214. if (empty($this->wheres)) {
  215. return $query;
  216. }
  217. //处理and逻辑
  218. if (isset($this->wheres['must'])) {
  219. if (isset($this->wheres['must']['where'])) {
  220. foreach ($this->wheres['must']['where'] as $value) {
  221. $must_data[]=[
  222. "match_phrase"=>[$value['field'] => $value['value']]
  223. ];
  224. }
  225. }
  226. if (isset($this->wheres['must']['range'])) {
  227. foreach ($this->wheres['must']['range'] as $value) {
  228. $must_data[]=[
  229. "range"=>[$value['field'] => $value['value']]
  230. ];
  231. }
  232. }
  233. }
  234. if (isset($this->wheres['in'])) {
  235. if (isset($this->wheres['in']['terms'])) {
  236. foreach ($this->wheres['in']['terms'] as $value) {
  237. $must_data[]=[
  238. "terms"=>[$value['field'] => $value['value']]
  239. ];
  240. }
  241. }
  242. if (isset($this->wheres['in']['phrase'])) {
  243. $sub_data = [];
  244. foreach ($this->wheres['in']['phrase'] as $value) {
  245. foreach ($value['value'] as $v) {
  246. $sub_data[]=[
  247. "match_phrase"=>[$value['field'] => $v]
  248. ];
  249. }
  250. }
  251. $must_data[] = ['bool' => ['should'=>$sub_data]];
  252. }
  253. }
  254. if (isset($this->wheres['must']['query'])) {
  255. $must_data=array_merge($must_data, $this->wheres['must']['query']);
  256. }
  257. //处理not逻辑
  258. if (isset($this->wheres['must_not'])) {
  259. if (isset($this->wheres['must_not']['where'])) {
  260. foreach ($this->wheres['must_not']['where'] as $value) {
  261. $must_not_data[]=[
  262. "match_phrase"=>[$value['field'] => $value['value']]
  263. ];
  264. }
  265. }
  266. if (isset($this->wheres['must_not']['range'])) {
  267. foreach ($this->wheres['must_not']['range'] as $value) {
  268. $must_not_data[]=[
  269. "range"=>[$value['field'] => $value['value']]
  270. ];
  271. }
  272. }
  273. }
  274. if (isset($this->wheres['not_in'])) {
  275. if (isset($this->wheres['not_in']['terms'])) {
  276. foreach ($this->wheres['not_in']['terms'] as $value) {
  277. $must_not_data[]=[
  278. "terms"=>[$value['field'] => $value['value']]
  279. ];
  280. }
  281. }
  282. if (isset($this->wheres['not_in']['phrase'])) {
  283. foreach ($this->wheres['not_in']['phrase'] as $value) {
  284. foreach ($value['value'] as $v) {
  285. $must_not_data[]=[
  286. "match_phrase"=>[$value['field'] => $v]
  287. ];
  288. }
  289. }
  290. }
  291. }
  292. if (isset($this->wheres['must_not']['query'])) {
  293. $must_not_data=array_merge($must_not_data, $this->wheres['must_not']['query']);
  294. }
  295. //处理or逻辑
  296. if (isset($this->wheres['should'])) {
  297. if (isset($this->wheres['should']['where'])) {
  298. foreach ($this->wheres['should']['where'] as $value) {
  299. $should_data[]=[
  300. "match_phrase"=>[$value['field'] => $value['value']]
  301. ];
  302. }
  303. }
  304. if (isset($this->wheres['should']['range'])) {
  305. foreach ($this->wheres['should']['range'] as $value) {
  306. $should_data[]=[
  307. "range"=>[$value['field'] => $value['value']]
  308. ];
  309. }
  310. }
  311. }
  312. if (isset($this->wheres['should_in'])) {
  313. if (isset($this->wheres['should_in']['terms'])) {
  314. foreach ($this->wheres['should_in']['terms'] as $value) {
  315. $should_data[]=[
  316. "terms"=>[$value['field'] => $value['value']]
  317. ];
  318. }
  319. }
  320. if (isset($this->wheres['should_in']['phrase'])) {
  321. foreach ($this->wheres['should_in']['phrase'] as $value) {
  322. foreach ($value['value'] as $v) {
  323. $should_data[]=[
  324. "match_phrase"=>[$value['field'] => $v]
  325. ];
  326. }
  327. }
  328. }
  329. }
  330. if (isset($this->wheres['should']['query'])) {
  331. $should_data=array_merge($should_data, $this->wheres['should']['query']);
  332. }
  333. if ($must_data) {
  334. $query['must']=$must_data;
  335. }
  336. if ($must_not_data) {
  337. $query['must_not']=$must_not_data;
  338. }
  339. if ($should_data) {
  340. $query['should']=$should_data;
  341. }
  342. if (isset($this->wheres['locations'])) {
  343. $data =[];
  344. foreach ($this->wheres['locations'] as $location) {
  345. $data[]=[
  346. "geo_distance"=>$location
  347. ];
  348. }
  349. $query['filter']=$data;
  350. }
  351. return $query;
  352. }
  353. }