PHP中使用ElasticSearch最新实例讲解

这篇文章主要介绍了PHP中使用ElasticSearch最新实例讲解,这篇文章的教程是比较详细,有需要的同学可以研究下。

网上很多关于ES的例子都过时了,版本很老,这篇文章的测试环境是ES6.5

通过composer安装

composer require 'elasticsearch/elasticsearch'

在代码中引入

require 'vendor/autoload.php';

use Elasticsearch\ClientBuilder;

$client = ClientBuilder::create()->setHosts(['172.16.55.53'])->build();

下面循序渐进完成一个简单的添加和搜索的功能。

首先要新建一个index:

index对应关系型数据(以下简称MySQL)里面的数据库,而不是对应MySQL里面的索引,这点要清楚。

  1. $params = [
  2. 'index' => 'myindex', #index的名字不能是大写和下划线开头
  3. 'body' => [
  4. 'settings' => [
  5. 'number_of_shards' => 2,
  6. 'number_of_replicas' => 0
  7. ]
  8. ]
  9. ];
  10. $client->indices()->create($params);

在MySQL里面,光有了数据库还不行,还需要建立表,ES也是一样的,ES中的type对应MySQL里面的表。

注意:ES6以前,一个index有多个type,就像MySQL中一个数据库有多个表一样自然,但是ES6以后,每个index只允许一个type,在往以后的版本中很可能会取消type。

type不是单独定义的,而是和字段一起定义

  1. $params = [
  2. 'index' => 'myindex',
  3. 'type' => 'mytype',
  4. 'body' => [
  5. 'mytype' => [
  6. '_source' => [
  7. 'enabled' => true
  8. ],
  9. 'properties' => [
  10. 'id' => [
  11. 'type' => 'integer'
  12. ],
  13. 'first_name' => [
  14. 'type' => 'text',
  15. 'analyzer' => 'ik_max_word'
  16. ],
  17. 'last_name' => [
  18. 'type' => 'text',
  19. 'analyzer' => 'ik_max_word'
  20. ],
  21. 'age' => [
  22. 'type' => 'integer'
  23. ]
  24. ]
  25. ]
  26. ]
  27. ];
  28. $client->indices()->putMapping($params);

在定义字段的时候,可以看出每个字段可以定义单独的类型,在first_name中还自定义了分词器 ik,

这个分词器是一个插件,需要单独安装的,参考另一篇文章:ElasticSearch基本尝试

现在数据库和表都有了,可以往里面插入数据了

概念:这里的 数据 在ES中叫文档

  1. $params = [
  2. 'index' => 'myindex',
  3. 'type' => 'mytype',
  4. //'id' => 1, #可以手动指定id,也可以不指定随机生成
  5. 'body' => [
  6. 'first_name' => '张',
  7. 'last_name' => '三',
  8. 'age' => 35
  9. ]
  10. ];
  11. $client->index($params);

多插入一点数据,然后来看看怎么把数据取出来:

通过id取出单条数据:

插曲:如果你之前添加文档的时候没有传入id,ES会随机生成一个id,这个时候怎么通过id查?id是多少都不知道啊。

所以这个插入一个简单的搜索,最简单的,一个搜索条件都不要,返回所有index下所有文档:

$data = $client->search();

现在可以去找一找id了,不过你会发现id可能长这样:zU65WWgBVD80YaV8iVMk,不要惊讶,这是ES随机生成的。

现在可以通过id查找指定文档了:

  1. $params = [
  2. 'index' => 'myindex',
  3. 'type' => 'mytype',
  4. 'id' =>'zU65WWgBVD80YaV8iVMk'
  5. ];
  6. $data = $client->get($params);

最后一个稍微麻烦点的功能:

注意:这个例子我不打算在此详细解释,看不懂没关系,这篇文章主要的目的是基本用法,并没有涉及到ES的精髓地方,

ES精髓的地方就在于搜索,后面的文章我会继续深入分析

  1. $query = [
  2. 'query' => [
  3. 'bool' => [
  4. 'must' => [
  5. 'match' => [
  6. 'first_name' => '张',
  7. ]
  8. ],
  9. 'filter' => [
  10. 'range' => [
  11. 'age' => ['gt' => 76]
  12. ]
  13. ]
  14. ]
  15. ]
  16. ];
  17. $params = [
  18. 'index' => 'myindex',
  19. // 'index' => 'm*', #index 和 type 是可以模糊匹配的,甚至这两个参数都是可选的
  20. 'type' => 'mytype',
  21. '_source' => ['first_name','age'], // 请求指定的字段
  22. 'body' => array_merge([
  23. 'from' => 0,
  24. 'size' => 5
  25. ],$query)
  26. ];
  27. $data = $this->EsClient->search($params);

上面的是一个简单的使用流程,但是不够完整,只讲了添加文档,没有说怎么删除文档,

下面我贴出完整的测试代码,基于Laravel环境,当然环境只影响运行,不影响理解,包含基本的常用操作:

  1. <?php
  2. use Elasticsearch\ClientBuilder;
  3. use Faker\Generator as Faker;
  4. /**
  5. * ES 的 php 实测代码
  6. */
  7. class EsDemo {
  8. private $EsClient = null;
  9. private $faker = null;
  10. /**
  11. * 为了简化测试,本测试默认只操作一个Index,一个Type,
  12. * 所以这里固定为 megacorp和employee
  13. */
  14. private $index = 'megacorp';
  15. private $type = 'employee';
  16. public function __construct(Faker $faker) {
  17. /**
  18. * 实例化 ES 客户端
  19. */
  20. $this->EsClient = ClientBuilder::create()->setHosts(['172.16.55.53'])->build();
  21. /**
  22. * 这是一个数据生成库,详细信息可以参考网络
  23. */
  24. $this->faker = $faker;
  25. }
  26. /**
  27. * 批量生成文档
  28. * @param $num
  29. */
  30. public function generateDoc($num = 100) {
  31. foreach (range(1,$num) as $item) {
  32. $this->putDoc([
  33. 'first_name' => $this->faker->name,
  34. 'last_name' => $this->faker->name,
  35. 'age' => $this->faker->numberBetween(20,80)
  36. ]);
  37. }
  38. }
  39. /**
  40. * 删除一个文档
  41. * @param $id
  42. * @return array
  43. */
  44. public function delDoc($id) {
  45. $params = [
  46. 'index' => $this->index,
  47. 'type' => $this->type,
  48. 'id' =>$id
  49. ];
  50. return $this->EsClient->delete($params);
  51. }
  52. /**
  53. * 搜索文档,query是查询条件
  54. * @param array $query
  55. * @param int $from
  56. * @param int $size
  57. * @return array
  58. */
  59. public function search($query = [], $from = 0, $size = 5) {
  60. // $query = [
  61. // 'query' => [
  62. // 'bool' => [
  63. // 'must' => [
  64. // 'match' => [
  65. // 'first_name' => 'Cronin',
  66. // ]
  67. // ],
  68. // 'filter' => [
  69. // 'range' => [
  70. // 'age' => ['gt' => 76]
  71. // ]
  72. // ]
  73. // ]
  74. //
  75. // ]
  76. // ];
  77. $params = [
  78. 'index' => $this->index,
  79. // 'index' => 'm*', #index 和 type 是可以模糊匹配的,甚至这两个参数都是可选的
  80. 'type' => $this->type,
  81. '_source' => ['first_name','age'], // 请求指定的字段
  82. 'body' => array_merge([
  83. 'from' => $from,
  84. 'size' => $size
  85. ],$query)
  86. ];
  87. return $this->EsClient->search($params);
  88. }
  89. /**
  90. * 一次获取多个文档
  91. * @param $ids
  92. * @return array
  93. */
  94. public function getDocs($ids) {
  95. $params = [
  96. 'index' => $this->index,
  97. 'type' => $this->type,
  98. 'body' => ['ids' => $ids]
  99. ];
  100. return $this->EsClient->mget($params);
  101. }
  102. /**
  103. * 获取单个文档
  104. * @param $id
  105. * @return array
  106. */
  107. public function getDoc($id) {
  108. $params = [
  109. 'index' => $this->index,
  110. 'type' => $this->type,
  111. 'id' =>$id
  112. ];
  113. return $this->EsClient->get($params);
  114. }
  115. /**
  116. * 更新一个文档
  117. * @param $id
  118. * @return array
  119. */
  120. public function updateDoc($id) {
  121. $params = [
  122. 'index' => $this->index,
  123. 'type' => $this->type,
  124. 'id' =>$id,
  125. 'body' => [
  126. 'doc' => [
  127. 'first_name' => '张',
  128. 'last_name' => '三',
  129. 'age' => 99
  130. ]
  131. ]
  132. ];
  133. return $this->EsClient->update($params);
  134. }
  135. /**
  136. * 添加一个文档到 Index 的Type中
  137. * @param array $body
  138. * @return void
  139. */
  140. public function putDoc($body = []) {
  141. $params = [
  142. 'index' => $this->index,
  143. 'type' => $this->type,
  144. // 'id' => 1, #可以手动指定id,也可以不指定随机生成
  145. 'body' => $body
  146. ];
  147. $this->EsClient->index($params);
  148. }
  149. /**
  150. * 删除所有的 Index
  151. */
  152. public function delAllIndex() {
  153. $indexList = $this->esStatus()['indices'];
  154. foreach ($indexList as $item => $index) {
  155. $this->delIndex();
  156. }
  157. }
  158. /**
  159. * 获取 ES 的状态信息,包括index 列表
  160. * @return array
  161. */
  162. public function esStatus() {
  163. return $this->EsClient->indices()->stats();
  164. }
  165. /**
  166. * 创建一个索引 Index (非关系型数据库里面那个索引,而是关系型数据里面的数据库的意思)
  167. * @return void
  168. */
  169. public function createIndex() {
  170. $this->delIndex();
  171. $params = [
  172. 'index' => $this->index,
  173. 'body' => [
  174. 'settings' => [
  175. 'number_of_shards' => 2,
  176. 'number_of_replicas' => 0
  177. ]
  178. ]
  179. ];
  180. $this->EsClient->indices()->create($params);
  181. }
  182. /**
  183. * 检查Index 是否存在
  184. * @return bool
  185. */
  186. public function checkIndexExists() {
  187. $params = [
  188. 'index' => $this->index
  189. ];
  190. return $this->EsClient->indices()->exists($params);
  191. }
  192. /**
  193. * 删除一个Index
  194. * @return void
  195. */
  196. public function delIndex() {
  197. $params = [
  198. 'index' => $this->index
  199. ];
  200. if ($this->checkIndexExists()) {
  201. $this->EsClient->indices()->delete($params);
  202. }
  203. }
  204. /**
  205. * 获取Index的文档模板信息
  206. * @return array
  207. */
  208. public function getMapping() {
  209. $params = [
  210. 'index' => $this->index
  211. ];
  212. return $this->EsClient->indices()->getMapping($params);
  213. }
  214. /**
  215. * 创建文档模板
  216. * @return void
  217. */
  218. public function createMapping() {
  219. $this->createIndex();
  220. $params = [
  221. 'index' => $this->index,
  222. 'type' => $this->type,
  223. 'body' => [
  224. $this->type => [
  225. '_source' => [
  226. 'enabled' => true
  227. ],
  228. 'properties' => [
  229. 'id' => [
  230. 'type' => 'integer'
  231. ],
  232. 'first_name' => [
  233. 'type' => 'text',
  234. 'analyzer' => 'ik_max_word'
  235. ],
  236. 'last_name' => [
  237. 'type' => 'text',
  238. 'analyzer' => 'ik_max_word'
  239. ],
  240. 'age' => [
  241. 'type' => 'integer'
  242. ]
  243. ]
  244. ]
  245. ]
  246. ];
  247. $this->EsClient->indices()->putMapping($params);
  248. $this->generateDoc();
  249. }
  250. }