Laravel Elasticsearch 增删改查

新建一个项目
1
$ laravel new elasticsearch
安装 elasticsearch 官方扩展包

为了更好的了解官方各种针对PHP的SDK,不使用其他改造过的扩展包,文档参考 https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ composer require elasticsearch/elasticsearch                     
Using version ^6.0 for elasticsearch/elasticsearch
./composer.json has been created
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 5 installs, 0 updates, 0 removals
- Installing psr/log (1.0.2): Downloading (100%)
- Installing react/promise (v2.7.0): Downloading (100%)
- Installing guzzlehttp/streams (3.0.0): Downloading (100%)
- Installing guzzlehttp/ringphp (1.1.1): Downloading (100%)
- Installing elasticsearch/elasticsearch (v6.0.1): Downloading (100%)
elasticsearch/elasticsearch suggests installing monolog/monolog (Allows for client-level logging and tracing)
Writing lock file
Generating autoload files
安装版版本目前最新为6.0

在MacOS下中使用brew安装对应版本的Elasticsearch6.x

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//先搜一下目前的版本
$ brew search elasticsearch
==> Formulae
elasticsearch elasticsearch@2.4 elasticsearch@5.6 ✔
//之前安装过elasticsearch@5.6,我这里先安装最新的版本,稍后从默认5.6切换到最新的6.x版本
$ brew install elasticsearch
//安装后再次列出
brew search elasticsearch
==> Formulae
elasticsearch ✔ elasticsearch@2.4 elasticsearch@5.6 ✔
//目前系统中就存在了两个版本
$ brew unlink elasticsearch@5.6 //取消旧版本
Unlinking /usr/local/Cellar/elasticsearch@5.6/5.6.10... 0 symlinks removed
//看下版本
$ elasticsearch -V
Version: 6.4.2, Build: oss/tar/04711c2/2018-09-26T13:34:09.098244Z, JVM: 1.8.0_172
//配置目录
Data: /usr/local/var/lib/elasticsearch/elasticsearch_loki/
Logs: /usr/local/var/log/elasticsearch/elasticsearch_loki.log
Plugins: /usr/local/var/elasticsearch/plugins/
Config: /usr/local/etc/elasticsearch/
//启动elasticsearch
$ brew services start elasticsearch
//注意安装elasticsearch之前一定要安装好jdk
访问Api地址
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ ~ » curl http://localhost:9200 
{
"name" : "cB7BsG7",
"cluster_name" : "elasticsearch_loki",
"cluster_uuid" : "oxevAVzTQHKkQUtVh_UQOA",
"version" : {
"number" : "6.4.2",
"build_flavor" : "oss",
"build_type" : "tar",
"build_hash" : "04711c2",
"build_date" : "2018-09-26T13:34:09.098244Z",
"build_snapshot" : false,
"lucene_version" : "7.4.0",
"minimum_wire_compatibility_version" : "5.6.0",
"minimum_index_compatibility_version" : "5.0.0"
},
"tagline" : "You Know, for Search"
}
回到代码中
1
2
//构建一个类Searchs.php
php artisan make:model Searchs
创建连接
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php

namespace App;

use Elasticsearch\ClientBuilder;
use Illuminate\Database\Eloquent\Model;

class Searchs extends Model
{
/**
* @var array
* 配置服务
*/
private $hosts = [
'localhost:9200'
];
/**
* @var array
* 索引与类型
*/
private $formats = [
'index' => 'test_index',
'type' => 'test_type',
];

/**
* @return \Elasticsearch\Client
* 创建连接
*/
private function setClient()
{
return ClientBuilder::create()->setHosts($this->hosts)->build();
}
}
创建索引和映射
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/**
* @return array
* 创建索引
*/
public function createdIndex()
{
$params = [
// //索引名(相当于mysql的数据库)
'index' => $this->formats['index'], //索引名称
'body' => [
'settings' => [
'number_of_shards' => 3, //分片数
'number_of_replicas' => 2 //副本数
],
//映射
'mappings' => [
//类型名(相当于mysql的表)
$this->formats['type'] => [
// 存储原始文档
'_source' => [
'enabled' => true
],
// 关闭所有字段的检索
'_all'=>[
'enabled' => 'false'
],
// 文档类型设置(相当于mysql的数据类型
'properties' => [
'first_name' => [
//字段类型为关键字,如果需要全文检索,则修改为text,注意keyword字段为整体查询,不能作为模糊搜索
'type' => 'keyword',
],
'age' => [
'type' => 'integer'
]
]
]
]
]
];
$result = $this->setClient()->indices()->create($params);
return $result;
}
先看一张图

20170315174547980.png

如图所示, 原始文档,有title和content两个字段,字段取值分别为”我是中国人”和” 热爱共产党”,这一点没什么可解释的。我们把原始文档写入Elasticsearch,默认情况下,Elasticsearch里面有2份内容,一份是原始文档,也就是_source字段里的内容,我们在Elasticsearch中搜索文档,查看的文档内容就是_source中的内容,这篇文档主要理解Document的操作,index和mapings放到下一篇讲解

增加文档
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 增加数据
* 注意这个变量在类中已经定义
* 在操作该方法前,将索引与类型都创建定义完成
*/
public function createData()
{
$this->formats['id'] = '001';
$this->formats['body'] = [
'first_name' => 'Tony',
'age' => 25
];
$result = $this->setClient()->index($this->formats);
return $result;
}
执行后返回,显示创建成功
1
2
3
4
5
6
7
8
9
10
11
12
13
14
array:8 [▼
"_index" => "test_index"
"_type" => "test_type"
"_id" => "001"
"_version" => 1
"result" => "created"
"_shards" => array:3 [▼
"total" => 2
"successful" => 1
"failed" => 0
]
"_seq_no" => 0
"_primary_term" => 1
]
查看数据
1
2
3
4
5
6
7
8
9
10
11
/**
* @return mixed
* 查看单条数据
* 通过指定ID
*/
public function getById()
{
$this->formats['id'] = '001';
$result = $this->setClient()->get($this->formats);
return $result;
}
返回数据
1
2
3
4
5
6
7
8
9
10
11
array:6 [▼
"_index" => "test_index"
"_type" => "test_type"
"_id" => "001"
"_version" => 1
"found" => true
"_source" => array:2 [▼
"first_name" => "Tony"
"age" => 25
]
]
更新文档
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* @return array
* 更新文档
* 根据ID更改first_name值
*/
public function updateData()
{
$this->formats['id'] = '001';
$this->formats['body'] = [
'doc' => [
'first_name' => 'Loki'
]
];
$result = $this->setClient()->update($this->formats);
return $result;
}
执行返回
1
2
3
4
5
6
7
8
9
10
11
12
13
14
array:8 [▼
"_index" => "test_index"
"_type" => "test_type"
"_id" => "001"
"_version" => 2
"result" => "updated"
"_shards" => array:3 [▼
"total" => 2
"successful" => 1
"failed" => 0
]
"_seq_no" => 1
"_primary_term" => 1
]
查看数据
1
2
3
4
5
6
7
8
9
10
11
array:6 [▼
"_index" => "test_index"
"_type" => "test_type"
"_id" => "001"
"_version" => 2
"found" => true
"_source" => array:2 [▼
"first_name" => "Loki"
"age" => 25
]
]
删除文档
1
2
3
4
5
6
7
8
9
10
 /**
* @return array
* 根据ID删除文档
*/
public function deleteData()
{
$this->formats['id'] = '001';
$result = $this->setClient()->delete($this->formats);
return $result;
}
执行返回
1
2
3
4
5
6
7
8
9
10
11
12
13
14
array:8 [▼
"_index" => "test_index"
"_type" => "test_type"
"_id" => "001"
"_version" => 3
"result" => "deleted"
"_shards" => array:3 [▼
"total" => 2
"successful" => 1
"failed" => 0
]
"_seq_no" => 2
"_primary_term" => 1
]
搜索查询

前面我们使用ID进行过单条的查询,实际Elasticsearch最大的两点在于文本上的检索

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* @return array
* 根据条件检索
*/
public function search()
{
$this->formats['body'] = [
'query' => [
'match' => [
'first_name' => 'Tony'
]
]
];
$result = $this->setClient()->search($this->formats);
return $result;
}
搜索结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
array:4 [▼
"took" => 4
"timed_out" => false
"_shards" => array:4 [▶]
"hits" => array:3 [▼
"total" => 2
"max_score" => 0.21110918
"hits" => array:2 [▼
0 => array:5 [▼
"_index" => "test_index"
"_type" => "test_type"
"_id" => "002"
"_score" => 0.21110918
"_source" => array:2 [▼
"first_name" => "Tony"
"age" => 25
]
]
1 => array:5 [▼
"_index" => "test_index"
"_type" => "test_type"
"_id" => "001"
"_score" => 0.16044298
"_source" => array:2 [▼
"first_name" => "Tony Hello"
"age" => 25
]
]
]
]
]
代码片段

https://gist.github.com/lokiqu/cd3085d2d59d216c1446a5217c6ba1fb