1.在yii2的项目目录中的composer.json
的require中加入:
"elasticsearch/elasticsearch": "~6.0"
2.然后执行
composer update
3.config/params.php中添加
'elasticsearch' => [
'192.168.163.128:9200'
],
4.新建一个EsService.php
<?php
namespace frontend\service;
use yii;
use Elasticsearch\ClientBuilder;
class EsService
{
public $index;
public $type;
public $client;
public function __construct($index, $type){
$this->index = $index;
$this->type = $type;
$hosts = yii::$app->params['elasticsearch'];
$this->client = ClientBuilder::create()->setHosts($hosts)->build();
}
/**
* 创建索引
*/
public function createIndex(){
$params = [
'index' => $this->index,
'body' => [
'settings' => [
'number_of_shards' => 2, //分片数
'number_of_replicas' => 0 //副本数
]
]
];
$response = $this->client->indices()->create($params);
return $response;
}
/**
* 删除索引
*/
public function deleteIndex(){
$params = ['index' => $this->index];
$response = $this->client->indices()->delete($params);
return $response;
}
/**
* 添加文档
*/
public function createDocument($id, $data){
$params = [
'index' => $this->index,
'type' => $this->type,
'id' => $id,
'body' => $data
];
$response = $this->client->index($params);
return $response;
}
/**
* 批量添加文档
*/
public function batchCreateDoc($data){
foreach ($data as $value){
$params = [
'index' => $this->index,
'type' => $this->type,
'body' => $value
];
$responses = $this->client->index($params);
}
return $responses;
}
/**
* 查询文档
*/
public function getDocument($id){
$params = [
'index' => $this->index,
'type' => $this->type,
'id' => $id,
'client' => [ 'ignore' => [400, 404] ],
];
$response = $this->client->get($params);
return $response;
}
/**
* 搜索文档
*/
public function searchDocument($param){
$tmp = [];
foreach ($param as $key => $value) {
$tmp[$key] = [
"query"=> $value,
"minimum_should_match"=> "50%",
];
}
$params = [
'index' => $this->index,
'type' => $this->type,
'body' => [
'query' => [
'match' => $tmp
]
]
];
$response = $this->client->search($params);
return $response;
}
/**
* @param $param
* @desc 关键词搜索文档
*/
public function keywordSearch($keyword){
$params = [
'index' => $this->index,
'type' => $this->type,
'body' => [
'query' => [
'multi_match' => [
'query'=>$keyword,
],
]
]
];
$response = $this->client->search($params);
return $response;
}
}
//在控制器里面操作
<?php
namespace frontend\controllers;
use yii\web\Controller;
use frontend\service\EsService;
/**
* Es controller
*/
class EsController extends Controller
{
/**
* Displays homepage.
*
* @return mixed
*/
public function actionIndex(){
$EsService = new EsService('mall', 'product');
$result = $EsService->createIndex();
$data = [
[
'name' => 'mongodb',
'nike_name' => 'NoSql',
'age' => '10',
'about' => 'this is mongodb and NoSql',
'interests' => 'sports music 量子专家',
],
[
'name' => 'MySql',
'nike_name' => 'Sql',
'age' => '22',
'about' => 'this is MySql and Sql',
'interests' => '作者是茂名量子专家',
],
[
'name' => '弗南永州锤子帮',
'nike_name' => '强小妮',
'age' => '32',
'about' => 'this is MySql and Sql',
'interests' => '强小妮是锤子帮大哥',
],
[
'name' => '弗北热干面',
'nike_name' => '热干面',
'age' => '32',
'about' => 'this is MySql and Sql',
'interests' => '包子加热干面法力无边',
],
];
//$result = $EsService->createDocument('', $ins);
//$result = $EsService->batchCreateDoc($data);
//$result = $EsService->keywordSearch('包');
echo "<pre>";
print_r($result);
echo "</pre>";
exit;
//return $this->render('index');
}
}
5.yii2还提供了一个操作Es的类 yii2-elasticsearch
首先引入 yii2-elasticsearch 操作类
composer.json的require中添加:
"yiisoft/yii2-elasticsearch": "~2.0.0"
然后执行:composer update
config/web.php的components中添加:
'components' => [
...
'elasticsearch' => [
'class' => 'yii\elasticsearch\Connection',
'nodes' => [
['http_address' => '127.0.0.1:9200']
],
'autodetectCluster' => false
],
],
6.参考某个大佬写了一个公共的类 common\Elasticsearch.php
<?php
namespace app\common;
use yii;
use yii\elasticsearch\ActiveRecord;
use yii\data\Pagination;
class Elasticsearch extends ActiveRecord{
/**
* 使用的数据库连接
*/
public static function getDb(){
return \Yii::$app->get('elasticsearch');
}
/**
* [mapConfig mapping配置]
* 返回这个模型的映射
*
* properties配置说明
*
* 属性
* 数据类型 string(已废弃) byte short integer long float double boolean date binary(二进制) ip(以字符换格式存IPv4地址) token_count(存储索引的字数信息)
*
* 公共属性
* index -> analyzed(被分析,编入索引,产生的token能被搜索到) not_analyzed(不被分析,使用原始值编入索引,在索引中作为单个词) no(不编入索引,无法搜索该字段)
* store -> 指定是否将字段的原始值写入索引,默认值是no,字段值被分析,能够被搜索,但是,字段值不会存储,这意味着,该字段能够被查询,但是不会存储字段的原始值 通常情况字段值已经是_source字段的一部分,可以只检索需要的
* boost -> 字段级别的助推,默认值是1,定义了字段在文档中的重要性/权重
* include_in_all -> 该属性指定当前字段是否包括在_all字段中,默认值是true
* copy_to -> 该属性指定一个字段名称,ElasticSearch引擎将当前字段的值复制到该属性指定的字段中
* doc_values -> 文档值是存储在硬盘上的索引时(indexing time)数据结构,对于not_analyzed字段,默认值是true,analyzed string字段不支持文档值;如果您确定不需要对字段进行排序或聚合,或者从脚本访问字段值,则可以禁用doc值以节省磁盘空间
* fielddata -> 字段数据是存储在内存中的查询时(querying time)数据结构,只支持analyzed string字段
* null_value -> 该属性指定一个值,当字段的值为NULL时,该字段使用null_value代替NULL值;在ElasticSearch中,NULL 值不能被索引和搜索,当一个字段设置为NULL值,ElasticSearch引擎认为该字段没有任何值,使用该属性为NULL字段设置一个指定的值,使该字段能够被索引和搜索。
*
* 常用其他属性
* analyzer -> 该属性定义用于建立索引和搜索的分析器名称,默认值是全局定义的分析器名称,该属性可以引用在配置结点(settings)中自定义的分析器
* search_analyzer -> 该属性定义的分析器,用于处理发送到特定字段的查询字符串
* ignore_above -> 该属性指定一个整数值,当字符串字段(analyzed string field)的字节数量大于该数值之后,超过长度的部分字符数据将不能被analyzer处理,不能被编入索引;对于 not analyzed string字段,超过长度的部分字符将被忽略,不会被编入索引。默认值是0,禁用该属性;
* position_increment_gap -> 该属性指定在相同词的位置上增加的gap,默认值是100;
* index_options -> 索引选项控制添加到倒排索引(Inverted Index)的信息
* [
* docs -> 只索引文档编号(Doc Number)
* freqs -> 索引文档编号和词频率(term frequency)
* positions -> 索引文档编号,词频率和词位置(序号)
* offsets -> 索引文档编号,词频率,词偏移量(开始和结束位置)和词位置(序号)
* 默认情况下,被分析的字符串(analyzed string)字段使用positions,其他字段使用docs
* ]
*
* 数值类型的其他属性
* precision_step -> 该属性指定为数值字段每个值生成的term数量,值越低,产生的term数量越高,范围查询越快,索引越大,默认值是4
* ignore_malformed -> 忽略格式错误的数值,默认值是false,不忽略错误格式,对整个文档不处理,并且抛出异常
* coerce -> 默认值是true,尝试将字符串转换为数值,如果字段类型是整数,那么将小数取整
*
* 日期类型的其他属性
* format -> 指定日期的格式,例如:“yyyy-MM-dd hh:mm:ss”
* ignore_malformed -> 忽略错误格式,默认值是false,不忽略错误格式
*
* fields -> 在fields属性中定义一个或多个字段,该字段的值和当前字段值相同,可以设置一个字段用于搜索,一个字段用于排序等
* "properties":
* {
* "id":{
* "type":"long",
* "fields":{
* "id2":{"type":"long","index":"not_analyzed"}
* }
* }
* }
* _all -> 表示存储其他字段的数据以便搜索,默认情况下,_all字段是启用的,包含了索引中所有字段的数据,然而这一字段使索引变大,如果不需要,请禁用该字段,或排除某些字段
* "_all":{"enabled":false}
* _source -> 表示在生成索引的过程中,存储发送到ElasticSearch的原始JSON文档,默认情况下,该字段会被启用,因为索引的局部更新功能依赖该字段。
* _routing -> 路由字段 公式:shard_num = hash(_routing) % num_primary_shards 使用的默认字段是_id,设置required为true,表示路由字段在进行索引的CRUD操作时必需显式赋值。
*
* 不可配置的元字段
* _index -> 返回文档所属的索引
* _uid -> 返回文档的type和id
* _type -> 返回文档类型(type)
* _id -> 返回文档的ID;
* _size -> 返回文档的_source字段中函数的字节数量;
* _field_names -> 返回文档中不包含null值的字段名称;
*
*/
public static function mapConfig(){
return [
// 根据type来获取model->attributes
'member' => [
'properties' => [
'user_id' => ['type' => 'integer'],
'user_name' => ['type' => 'text'],
'email' => ['type' => 'keyword'],
'qq' => ['type' => 'keyword'],
'edit_time' => ['type' => 'date', 'format' => 'yyyy-MM-dd HH:mm:ss||yyyy-MM-dd']
]
],
// 根据type来获取model->attributes
'member2' => [
'properties' => [
'user_id' => ['type' => 'integer'],
'user_name' => ['type' => 'text'], 'edit_time' => ['type' => 'date', 'format' => 'yyyy-MM-dd HH:mm:ss||yyyy-MM-dd']
]
]
];
}
/**
* 获取群集中所有索引映射
*/
public static function getMapping(){
$db = self::getDb();
$command = $db->createCommand();
return $command->getMapping();
}
/**
* 根据索引主键获取相关信息
* 支持单个或多个
*/
public function getByKey($id){
if(is_array($id)){
$res = self::mget($id);
}else{
$res = self::get($id);
}
return $res;
}
/**
* 单个
* 默认返回object对象 返回数组 添加->asArray()
*/
public function getOne($query = []){
$es_query = self::find();
// 匹配查询
if($query && !empty($query)){
$es_query->query($query);
}
// 分组
$res = $es_query->one();
return $res;
}
/**
* 列表
* 默认返回object对象 返回数组 添加->asArray()
* search 与 all 区别在于 all是在search基础上处理再拿出结果
*/
public function getList($query = [], $order = [], $offset = 0, $limit = 20){
$es_query = self::find();
// 匹配查询
if($query && !empty($query)){
$es_query->query($query);
}
// 排序
if($order && !empty($order)){
$es_query->orderby($order);
}
// 分组
$res = $es_query->offset($offset)->limit($limit)->asArray()->all();
$list = array_column($res, '_source');
return $list;
}
/**
* 分页列表
* 默认返回object对象 返回数组 添加->asArray()
* search 与 all 区别在于 all是在search基础上处理再拿出结果
*/
public function getPageList($query = [], $order = []){
$es_query = self::find();
// 匹配查询
if($query && !empty($query)){
$es_query->query($query);
}
// 排序
if($order && !empty($order)){
$es_query->orderby($order);
}
// 分组
$count = $es_query->search();
// 分页
$pages = new Pagination(['totalCount' => $count['hits']['total']]);
// 分组
$res = $es_query->offset($pages->offset)->limit($pages->limit)->asArray()->all();
$list = array_column($res, '_source');
return ['list' => $list, 'pages' => $pages];
}
/**
* 列表
* 默认返回object对象 返回数组 添加->asArray()
* search 与 all 区别在于 all是在search基础上处理再拿出结果
*/
public function getFilterList($filter_arr = [], $query = [], $order = [], $offset = 0, $limit = 20){
$es_query = self::find();
// 过滤器
if($filter_arr && !empty($filter_arr)){
$es_query->postFilter($filter_arr);
}
// 匹配查询
if($query && !empty($query)){
$es_query->query($query);
}
// 排序
if($order && !empty($order)){
$es_query->orderby($order);
}
// 分组
$res = $es_query->offset($offset)->limit($limit)->all();
return $res;
}
/**
* 获取高亮列表
* 默认返回object对象 返回数组 添加->asArray()
* search 与 all 区别在于 all是在search基础上处理再拿出结果
* 循环使用$v->highlight获取高亮列表
*/
public function getHighLightList($highlight_arr = [], $query = [], $offset = 0, $limit = 20){
$es_query = self::find();
// 高亮
if($highlight_arr && !empty($highlight_arr)){
$es_query->highlight($highlight_arr);
}
// 匹配查询
if($query && !empty($query)){
$es_query->query($query);
}
// 分组
$res = $es_query->offset($offset)->limit($limit)->all();
return $res;
}
/**
* 获取聚合列表
* 默认返回object对象 返回数组 添加->asArray()
* search 与 all 区别在于 all是在search基础上处理再拿出结果
*/
public function getAggList($aggregate_name, $addAggregate_arr = [], $query = [], $offset = 0, $limit = 20){
$es_query = self::find();
// 聚合
if($addAggregate_arr && !empty($addAggregate_arr)){
$es_query->addAggregate($aggregate_name, $addAggregate_arr);
}
// 匹配查询
if($query && !empty($query)){
$es_query->query($query);
}
// 分组
$res = $es_query->offset($offset)->limit($limit)->search();
return ['list' => $res['hits']['hits'], $aggregate_name => $res['aggregations'][$aggregate_name]];
}
}
7.新建一个model model/EsModel
<?php
namespace app\models;
use app\common\Elasticsearch;
class EsModel extends Elasticsearch{
// _index _type _id 定义
// https://www.elastic.co/guide/cn/elasticsearch/guide/current/_Document_Metadata.html
public static $index_db_name = '';
public static $type_tb_name = '';
// 索引名相当于库名
public static function index(){
return self::$index_db_name;
}
// 类别名相当于表名
public static function type(){
return self::$type_tb_name;
}
// 属性
public function attributes(){
$mapConfig = self::mapConfig();
return array_keys($mapConfig[self::$type_tb_name]['properties']);
}
// 映射
public static function mapping(){
$mapConfig = self::mapConfig();
return [
static::type() => $mapConfig[self::$type_tb_name]
];
}
// 更新映射
public static function updateMapping(){
$db = self::getDb();
$command = $db->createCommand();
if(!$command->indexExists(self::index())){
$command->createIndex(self::index());
}
$res = $command->setMapping(self::index(), self::type(), self::mapping());
return $res;
}
// 创建索引
public static function createIndex(){
$db = static::getDb();
$command = $db->createCommand();
$command->createIndex(static::index(), [
'settings' => [
'index' => [
// 指定新索引的时候不会立即生效,1s之后刷新生效 默认是1s
'refresh_interval' => '1s',
// 索引分片个数 默认5片
'number_of_shards' => 5,
// 每个分片副本个数 默认1个
'number_of_replicas' => 1
]
],
'mappings' => static::mapping(),
//'warmers' => [ /* ... */ ],
//'aliases' => [ /* ... */ ],
//'creation_date' => '...'
]);
}
// 删除索引
public static function deleteIndex(){
$db = static::getDb();
$command = $db->createCommand();
$res = $command->deleteIndex(static::index(), static::type());
return $res;
}
}
8.controller调用
$model = new \app\models\EsModel();
$model::$index_db_name = 'index_name';
$model::$type_tb_name = 'type_name';