php elasticsearch 教程

作者: JONE 分类: 编程 发布时间: 2022-01-24 21:33

原文链接:https://www.tizi365.com/archives/951.html

PDF  https://www.jone.xyz/datafile/php elasticsearch 教程.pdf

一、php elasticsearch 教程

php elasticsearch教程,主要从php角度讲解elasticsearch的增删改查等操作。

提示:如果不熟悉Elasticsearch的相关概念和查询语法,请参考:Elasticsearch 教程,这里不再重复介绍ES的核心概念和查询语法。

php elasticsearch 教程,主要围绕ES官方php客户端进行讲解。

版本说明

注意自己的Php版本和Elasticsearch版本的对应关系,选择合适的php elasticsearch客户端版本。

Elasticsearch版本 php ES客户端版本 php版本
>= 7.0, < 8.0 >= 7.0 > 7.1
>= 6.6, ⇐ 6.7 6.7.x > 7.0
>= 6.0, ⇐ 6.5 6.5.x > 7.0
>= 5.0, < 6.0 5.5.0 > 5.6, < 7.0

最新的php es客户端版本是:7.8.0, 需要Php7.1以上,如果需要支持es 5版本,选择es客户端版本5.5.0即可,php5.6就可以使用。

安装依赖

使用Composer方式安装

依赖配置

{
    "require": {
        "elasticsearch/elasticsearch": "~7.0"
    }
}

安装

切换到项目目录,执行命令。

php composer install

提示:关于composer命令路径,安装composer后,将composer命令路径添加到PATH环境变量即可。

加载依赖

在php入口文件,加载autoload脚本,就可以自动加载composer安装的第三方包。

require 'vendor/autoload.php';

创建client

在使用ES之前,需要先创建一个ES client对象,用于配置Elasticsearch连接地址,账号、密码、发送ES请求等等。

use Elasticsearch\ClientBuilder;

// ES服务端配置,这里配置两个ES服务地址,这里是免密码访问的配置方式。
$hosts = [
    'localhost:9200', 
    'localhost:9201', 
];

$client = ClientBuilder::create()           // 实例化一个ClientBuilder对象,通过他配置client
                    ->setHosts($hosts)      // 设置ES服务端配置
                    ->build();              // 创建Client

插入文档

$params = [
    'index' => 'my_index', // 索引名
    'id'    => 'my_id', // 文档id
    'body'  => ['testField' => 'abc'] // 文档内容,最终会转成json,因此支持任意结构
];

// 通过client::index方法,插入文档,如果
$response = $client->index($params);
print_r($response);

输出结果

Array
(
    [_index] => my_index // 索引名
    [_type] => _doc // 新版ES已经没什么作用了
    [_id] => my_id // 文档id
    [_version] => 1 // 文档版本号
    [created] => 1
)

提示:es 的index操作,除了插入文档,其实也可以更新文档,如果文档id,已经存在就会更新文档,不过这里的更新操作是全量更新,就是新更新的文档内容会覆盖掉老的文档,而不是局部更新,例如:老的文档内容包含order_id,title两个字段,通过index更新title字段内容,那么新的文档内容只有title字段,order_id字段被丢去了,如果非要使用index实现更新操作,则需要把所有老的字段都写一遍。

读取文档

根据文档id查询内容

$params = [
    'index' => 'my_index',// 索引名 
    'id'    => 'my_id' // 需要查询的文档id
];

// 执行请求
$response = $client->get($params);
print_r($response);

输出结果

Array
(
    [_index] => my_index // 索引名
    [_type] => _doc
    [_id] => my_id // 文档id
    [_version] => 1
    [found] => 1
    [_source] => Array  // 文档内容
        (
            [testField] => abc
        )

)

搜索文档

$params = [
    'index' => 'my_index',  // 索引名
    'body'  => [ // ES查询语法
        'query' => [
            'match' => [
                'testField' => 'abc'
            ]
        ]
    ]
];

// 执行ES请求
$response = $client->search($params);
print_r($response);

输出结果

Array
(
    [took] => 1   // 执行时间
    [timed_out] => // 是否超时
    [_shards] => Array  
        (
            [total] => 5
            [successful] => 5
            [failed] => 0
        )

    [hits] => Array  // 搜索结果
        (
            [total] => 1   // 匹配文档数量
            [max_score] => 0.30685282 // 匹配分值
            [hits] => Array  // 匹配文档内容数组,下面就是匹配的一个个文档内容
                (
                    [0] => Array
                        (
                            [_index] => my_index
                            [_type] => _doc
                            [_id] => my_id
                            [_score] => 0.30685282
                            [_source] => Array
                                (
                                    [testField] => abc
                                )
                        )
                )
        )
)

删除文档

$params = [
    'index' => 'my_index', // 索引名
    'id'    => 'my_id' // 文档id
];

// 执行删除请求
$response = $client->delete($params);
print_r($response);

输出结果

Array
(
    [found] => 1 // 是否匹配文档
    [_index] => my_index // 索引名
    [_type] => _doc
    [_id] => my_id // 删除的文档id
    [_version] => 2
)

删除索引

$deleteParams = [
    'index' => 'my_index' // 索引名
];
$response = $client->indices()->delete($deleteParams);
print_r($response);

输出

Array
(
    [acknowledged] => 1 // es服务端接受处理
)

其他详细介绍,请参考后续章节。

二、php elasticsearch连接配置

php的elasticsearch连接配置主要通过ClientBuilder工具类完成。

常用的配置项如下:

  • elasticsearch连接地址
  • elasticsearch认证账号和密码
  • 请求重试次数

格式1

// 直接配置多个ES服务地址,支持多种类型的地址
$hosts = [
    '192.168.1.1:9200',         // IP + Port
    '192.168.1.2',              // 仅 IP
    'mydomain.server.com:9201', // 域名 + Port
    'mydomain2.server.com',     // 仅 域名
    'https://localhost',        // https协议格式
    'https://192.168.1.3:9200',  // https协议格式
    // 支持设置es连接的账号和密码
    'https://username:password@foo.com:9200/elastic'
];

$client = ClientBuilder::create()           // 创建 ClientBuilder
                    ->setHosts($hosts)      // 设置 hosts
                    ->build();              // 构建client对象

ES连接地址详解:

schema://username:password@host:port/path

参数说明:

  • schema – http协议类型,支持http和https
  • username – 账号
  • password – 密码
  • host – 域名或者ip地址
  • port – 端口号
  • path – url路径

ES连接地址例子

https://admin:123456@foo.com:9200/elastic

 

格式2

支持详细的配置Elasticsearch信息,支持配置账号和密码

// 每一个ES服务地址,是一个数组,支持配置详细的连接信息
hosts = [
    // 等价连接地址: "https://username:password!#$?*abc@foo.com:9200/elastic"
    [
        'host' => 'foo.com', // 域名
        'port' => '9200', // 端口
        'scheme' => 'https', // 协议
        'path' => '/elastic', // path
        'user' => 'username', // 账号
        'pass' => 'password!#$?*abc' // 密码
    ],

    // 等价连接地址 "http://localhost:9200/"
    [
        'host' => 'localhost',    // 仅配置域名
    ]
];

$client = ClientBuilder::create()           // 创建 ClientBuilder对象
                    ->setHosts($hosts)      // 设置 hosts
                    ->build();              // 构建client对象

请求重试次数

$client = ClientBuilder::create()
                    ->setRetries(2) // 设置连接请求次数为2
                    ->build();

三、php elasticsearch 文档操作(CRUD)

Elasticsearch文档的基础操作主要包括:创建、查询、更新、删除、批量查询、批量更新、批量删除。

下面介绍php对elasticsearch文档的基础操作

创建文档

$params = [
    'index' => 'my_index', // 索引名
    'id'    => 'my_id', // 设置文档Id, 可以忽略Id, Es也会自动生成
    'body'  => [ 'testField' => 'abc'] // 设置文档内容
];

// 创建文档
$response = $client->index($params);

bulk批量创建文档

通过bulk实现批量插入文档,bulk操作,都是一行操作说明,一行操作相关数据的方式进行组织内容。

// 循环插入100条数据
for($i = 0; $i < 100; $i++) {
    // bulk操作,先拼接一行index操作参数
    $params['body'][] = [
        'index' => [
            '_index' => 'my_index', // 索引名
            'id'    => 'my_id', // 设置文档Id, 可以忽略Id, Es也会自动生成
	    ]
    ];
   
    // 接着拼接index操作的内容,这里就是我们需要插入的文档内容
    $params['body'][] = [
        'my_field'     => 'my_value',
        'second_field' => 'some more values'
    ];
}

// 执行bulk操作
$responses = $client->bulk($params);

查询文档

根据文档id查询

$params = [
    'index' => 'my_index', // 索引名
    'id'    => 'my_id' // 需要查询的文档id
];

// 执行请求
$response = $client->get($params);

局部更新文档

$params = [
    'index' => 'my_index', // 索引名
    'id'    => 'my_id', // 文档id
    'body'  => [ // ES请求体内容
        'doc' => [ // doc包含的内容就是我们想更新的字段内容
            'new_field' => 'abc'
        ]
    ]
];

// 执行ES请求
$response = $client->update($params);

update by query

根据查询条件匹配更新内容

$params = [
    'index' => 'my_index', // 索引名
    // 如果出现版本冲突,如何处理?proceed表示继续更新,abort表示停止更新
    'conflicts' => 'proceed', 
    'body' => [ // ES请求体内容
        // 通过script更新文档内容,ctx._source代表匹配到的文档
        // 含义等于 counter字段值 + 1
        'script' => 'ctx._source.counter++',
        'query' => [ // 设置查询条件,跟es查询语法一致
            "term" => [
                'user_id' => 'kimchy'
            ]
        ],
    ],
];
$response = $client->updateByQuery($params);

提示:ES查询语法,请参考:Elasticsearch查询语法,只要将ES查询语法转换成PHP数组即可

Upserts

更新文档内容,如果文档不存在则插入文档。

$params = [
    'index' => 'my_index', // 索引名
    'id'    => 'my_id', // 文档id
    'body'  => [ // es请求体
        'script' => [ // 通过脚本更新内容
            // 设置脚本内容,ctx._source代表匹配的文档内容,脚本含义: counter字段值 + 脚本参数count
            'source' => 'ctx._source.counter += params.count',
            'params' => [ // 设置脚本参数
                'count' => 4
            ],
        ],
        // 如果文档不存在,则插入upsert设置的内容
        // upsert的内容就相当于默认值
        'upsert' => [
            'counter' => 1
        ],
    ]
];

// 执行请求
$response = $client->update($params);

删除文档

根据文档Id删除文档

$params = [
    'index' => 'my_index', // 索引名
    'id'    => 'my_id' // 文档id
];

// 执行请求
$response = $client->delete($params);

delete by query

根据查询条件,批量删除文档

$params = [
    'index' => 'my_index', // 索引名
    // 如果出现版本冲突,如何处理?proceed表示继续更新,abort表示停止更新
    'conflicts' => 'proceed',
    'body' => [ // ES请求体内容
        'query' => [ // 设置查询条件,跟es查询语法一致
            "term" => [
                'user_id' => 'kimchy'
            ]
        ],
    ],
];
$client->deleteByQuery($params);

四、php elasticsearch 索引管理

php elasticsearch 索引管理常用操作主要包括:创建索引、删除索引、查询索引结构,修改索引设置。

创建索引

虽然,ES可以自动创建索引,不过实际项目中,通常需要预先创建索引结构,明确指定数据类型,避免出现ES自动创建的字段类型不是你想要的类型。

$client = ClientBuilder::create()->build();
$params = [
    'index' => 'my_index', // 索引名
    'body' => [ // es 索引结构定义
        'settings' => [ // 索引配置
            'number_of_shards' => 3, // 分片数量
            'number_of_replicas' => 2 // 副本数量
        ],
        'mappings' => [ // mapping定义,即索引结构定义
            '_source' => [
                'enabled' => true
            ],
            'properties' => [
                'first_name' => [
                    'type' => 'keyword'
                ],
                'age' => [
                    'type' => 'integer'
                ]
            ]
        ]
    ]
];


// 创建索引
$response = $client->indices()->create($params);

ES中mappings负责索引字段和数据类型,具体的ES mapping语法,请参考:Elasticsearch mapping,将ES的mapings定义的json结构转成php数组即可,

删除索引

$params = [
   'index' => 'my_index' // 索引名
]; 
$response = $client->indices()->delete($params);

查询索引结构

查询首页的mapping定义

// 查询所有的mapping定义
$response = $client->indices()->getMapping();

// 查询指定索引的Mapping定义
$params = [
    'index' => 'my_index' // 索引名
];
$response = $client->indices()->getMapping($params);

// 查询my_index和my_index2两个索引的mapping定义
$params = [
    'index' => [ 'my_index', 'my_index2' ]
];
$response = $client->indices()->getMapping($params);

修改索引设置

$params = [
    'index' => 'my_index', // 索引名
    'body' => [
        'settings' => [ // 修改设置
            'number_of_replicas' => 5, // 副本数
        ]
    ]
];

$response = $client->indices()->putSettings($params);

五、php elasticsearch 搜索详解

本章主要讲解php Elasticsearch的搜索的写法,大体上php Elasticsearch的写法还是跟elasticsearch查询语法保持一致,区别就是elasticsearch使用的是json结构,需要转换成php数组。

如果不熟悉elasticsearch查询语法和相关概念,可以先看看elasticsearch查询语法教程,这里不再重复。

下面通过一些例子对比下,elasticsearch查询语法和php的写法之间的区别

php es查询语法差异

es查询语法

curl -XGET 'localhost:9200/my_index/_search' -d '{
    "query" : {
        "match" : {
            "testField" : "abc"
        }
    }
}'

转换成php后的写法

$params = [
    'index' => 'my_index', // 索引名
     //body保存es 请求体内容, 这里的内容跟es查询语法保持一致,区别就是需要转成php数组格式
    'body'  => [ 
        // 这里的内容跟上面查询语法一致
        'query' => [
            'match' => [
                'testField' => 'abc'
            ]
        ]
    ]
];

// 通过search执行查询请求。
$results = $client->search($params);

提示:php elasticsearch的查询语法跟elasticsearch查询语法完全一致,只要将json格式转换成php数组即可, 详情参考:elasticsearch查询语法

处理搜索结果

$params = [
    'index' => 'my_index',
    'body'  => [
        'query' => [
            'match' => [
                'testField' => 'abc'
            ]
        ]
    ]
];

$results = $client->search($params);

// 下面处理查询结果
$milliseconds = $results['took']; // 获取请求执行时间,单位毫秒
// 获取匹配的最大分值
$maxScore     = $results['hits']['max_score'];

// 获取匹配的文档结果,是一个文档列表,建议打印出来看看
$list = $results['hits']['hits'];

复杂的查询例子

es查询例子

curl -XGET 'localhost:9200/my_index/_search' -d '{
    "query" : {
        "bool" : {
            "filter" : {
                "term" : { "my_field" : "abc" }
            },
            "should" : {
                "match" : { "my_other_field" : "xyz" }
            }
        }
    }
}'

转换成php代码

$params = [
    'index' => 'my_index', // 索引名
    'body'  => [ // es 请求体,下面的内容,仔细跟上面对比下,完全一致
        'query' => [
            'bool' => [
                'filter' => [
                    'term' => [ 'my_field' => 'abc' ]
                ],
                'should' => [
                    'match' => [ 'my_other_field' => 'xyz' ]
                ]
            ]
        ]
    ]
];


$results = $client->search($params);

分页

$params = [
    'index' => 'my_index', // 索引名
    'from' => 0, // 分页参数, 开始偏移配置
    'size' => 100, // 分页参数 - 分页大小,默认 10
    'body'  => [// es查询条件
        'query' => [
            'match' => [
                'testField' => 'abc'
            ]
        ]
    ]
];

// 通过search执行查询请求。
$results = $client->search($params);

排序

$params = [
    'index' => 'my_index', // 索引名
    'from' => 0, // 分页参数, 开始偏移配置
    'size' => 100, // 分页参数 - 分页大小,默认 10
    'sort' => [ // 设置排序条件, 支持多个排序字段
        'shop_id' => [ // 排序字段
            'order' => 'desc' // 排序方向: asc升序,desc降序
        ]
    ],
    'body'  => [// es查询条件
        'query' => [
            'match' => [
                'testField' => 'abc'
            ]
        ]
    ]
];

// 通过search执行查询请求。
$results = $client->search($params);

六、php elasticsearch 聚合查询(Aggregation)

Elasticsearch中的聚合查询,类似SQL的SUM/AVG/COUNT/GROUP BY分组查询,主要用于统计分析场景。

这里主要介绍PHP Elasticsearch 聚合查询的写法,如果不了解ES聚合查询,请参考 ES聚合查询基本概念和语法

提示:ES聚合查询语法使用的是json格式描述,在php中使用需要转换成php数组描述

例子

下面是ES通过rest api执行聚合查询的例子,aggs字段描述的就是聚合查询语句。

GET /order/_search
{
    "size" : 0, // 设置size=0的意思就是,仅返回聚合查询结果,不返回普通query查询结果。
    "aggs" : { // 聚合查询语句的简写
        "popular_colors" : { // 给聚合查询取个名字,叫popular_colors
            "terms" : { // 聚合类型为,terms,terms是桶聚合的一种,类似SQL的group by的作用,根据字段分组,相同字段值的文档分为一组。
              "field" : "color" // terms聚合类型的参数,这里需要设置分组的字段为color,根据color分组
            }
        }
    }
}

翻译成PHP代码则写法如下

$params = [
    'index' => 'order', // 索引名
    'size' => 0, // 设置0,表示不返回匹配结果,仅返回聚合查询统计结果
    'body'  => [// es请求体内容
        'aggs' => [ // 聚合查询语句,这里的语法结构跟ES聚合查询语句一致
            'popular_colors' => [
                'terms' => [
                    'field' => 'color'
                ]
            ]
        ]
    ]
];

// 通过search执行查询请求。
$results = $client->search($params);
// 聚合分析结构通常保存在$results['aggregations'] 字段中,可以打印$results观察下,输出的内容,基本上跟ES restful api查询的结果类似。

php的aggs聚合查询语句跟ES聚合查询语法一致,区别就是一个是json格式一个是php数组格式。