mawebcoder / laravel-elasticsearch
laravel的Elasticsearch ORM包
Requires
- guzzlehttp/guzzle: ^7.0
Requires (Dev)
- orchestra/testbench: ^8.0
README
使用Eloquent类似的查询构建器,你可以驯服这个野兽,无需担心Elasticsearch的复杂语法。
你可以使用这个包而不必深入研究Elasticsearch,通过不需要记住复杂的嵌套语法来节省时间。
依赖项
配置文件和Elasticsearch迁移日志
为了能够保存与迁移相关的日志并自定义你的配置,你需要运行以下命令
php artisan vendor:publish --tag=elastic
然后迁移你的数据库
php artisan migrate
配置
发布配置文件后,你会看到以下内容
return [
'index_prefix' => env('APP_NAME', 'elasticsearch'),
'host' => 'https://',
'port' => 9200,
'reindex_migration_driver' => "sync", //sync or queue,
"reindex_migration_queue_name" => 'default',
'base_migrations_path' => app_path('Elasticsearch/Migrations'),
'base_models_path' => app_path('Elasticsearch/Models'),
"username" => env('ELASTICSEARCH_USERNAME', null),
'password' => env('ELASTICSEARCH_PASSWORD', null)
];
ORM
此包为Laravel中的文档工作添加了ORM功能,使得它更容易使用,就像我们在Laravel中看到的那样。我们将随着进程的推进了解更多。让我们深入探讨。
模型
为了能够更有效地与我们的文档进行关联,我们需要为每个索引创建一个模型。与我们在Laravel中看到的模型相似,这大大简化了与数据库通信的工作。
创建模型
php artisan elastic:make-model <model-name>
默认情况下,你的模型基础路径位于app/Elasticsearch/Models
目录,但你可以在config/elasticsearch.php
文件中定义自己的基础路径。
你的所有模型都必须继承自BaseElasticsearchModel
类。这是一个抽象类,它强制你实现返回模型索引名的getIndex
方法。
public function getIndex():string
{
return 'articles';
}
我们使用此方法的返回值在迁移中创建你想要的索引。
如果你想通过你在配置文件中定义的前缀来获取你的索引名
$model->getIndexWithPrefix();
迁移
正如你所知,Elasticsearch使用映射来定义其文档的结构,这可能在原始形式中看起来有些困难。为了简化这个过程,我们使用迁移使其更容易。在定义模型后,你必须创建一个迁移来注册你希望的字段。你的所有迁移都必须继承自BaseElasticMigration
抽象类。
创建新的迁移
php artisan elastic:make-migration <migration-name>
默认情况下,你的迁移基础路径位于app/Elasticsearch/Migrations
目录,但你可以在config/elasticsearch.php
文件中定义自己的基础路径。
<?php
//app/Elasticsearch/Migrations
use Mawebcoder\Elasticsearch\Migration\BaseElasticMigration
use App\Elasticsearch\Models\EArticleModel;
return new class extends BaseElasticMigration {
public function getModel():string
{
return EArticleModel::class;
}
public function schema(BaseElasticMigration $mapper): void
{
$mapper->integer('id');
$mapper->string('name');
$mapper->boolean('is_active');
$mapper->text('details');
$mapper->integer('age');
$mapper->object('user',function($BaseElasticMigration $mapper){
return $mapper->string('name')
->object('values',function($mapper){
return $mapper->bigInt('id);
})
});
}
};
不幸的是,该包无法自动找到你的迁移路径。要引入迁移路径,将以下示例代码放在你的一个提供者中
use Mawebcoder\Elasticsearch\Facade\Elasticsearch;
public function register(): void
{
Elasticsearch::loadMigrationsFrom(__DIR__ . '/../Elastic/Migrations');
Elasticsearch::loadMigrationsFrom(__DIR__ . '/../App/Migrations');
}
查看迁移状态
php artisan elastic:migrate-status
迁移迁移并创建你的索引映射
php artisan elastic:migrate
重置所有迁移(此命令仅在所有迁移中运行down
方法)
php artisan elstic:migrate --reset
删除所有索引并重新注册它们
php artisan elastic:migrate --fresh
回滚迁移
php artisan elastic:migrate-rollback
默认情况下,此命令仅回滚一次迁移。如果你想自己确定步骤
php artisan elastic:migrate-rollback --step=<number>
字段类型
整数
$this->integer('age');
字符串(关键词)
$this->string('name');
对象
$this->object('categories',function($mapper){
return $mapper->string('name','teylor')
- >integer('parentM_id',22)
->object('sequences',function($mapper){
return $mapper->bigInt('id');
})
})
布尔值
$this->boolean('is_active');
小整数(短)
$this->smallInteger('age');
大整数(长)
$this->bigInteger('income');
双精度浮点数
$this->double('price');
浮点数
$this->float('income');
字节型整数(字节)
$this->tinyInt('value');
文本
$this->text(field:'description',fieldData:true);
日期时间
$this->datetime('created_at');
编辑索引映射
有时您需要修改您的映射。为此,您需要添加一个新的迁移
php artisan elastic:make-migration <alter migration name>
<?php
use Mawebcoder\Elasticsearch\Migration\BaseElasticMigration;
use Mawebcoder\Elasticsearch\Models\EArticleModel;
use Mawebcoder\Elasticsearch\Migration\AlterElasticIndexMigrationInterface;
return new class extends BaseElasticMigration implements AlterElasticIndexMigrationInterface {
public function getModel(): string
{
return EArticleModel::class;
}
public function schema(BaseElasticMigration $mapper): void
{
$mapper->dropField('name');
$mapper->boolean('new_field');//add this field to
}
public function alterDown(BaseElasticMigration $mapper): void
{
$mapper->string('name');
$mapper->dropField('new_field');
}
};
如您所见,我们在迁移中实现了AlterElasticIndexMigrationInterface
接口。然后在alterDown方法中,我们编写了我们的回滚场景。最后,迁移您的迁移
php artisan elastic:migrate
动态映射
默认情况下,Elasticsearch可以检测您在映射中未引入的字段类型,并自动定义其类型。该软件包默认禁用了此功能。要激活它,请在您的迁移中执行以下操作
protected bool $isDynamicMapping = true;
查询构建器
就像Laravel一样,它允许您通过使用一系列预定义的方法来创建复杂和简单的查询,这个软件包也使用了这个功能,为您提供类似的经验。
存储记录
$eArticleModel=new EArticleModel(); $eArticleModel->name='mohammad'; $eArticleModel->id=2; $eArticleModel->is_active=true; $eArticleModel->user=[ 'name'=>'komeil', 'id'=>3 ]; $eArticleModel->text='your text'; $eArticleModel->age=23; $eArticleModel->save();
- 注意:如果您没有传递映射中存在的任何字段,我们默认将其设置为null
存储多个记录(批量插入)
$users = [ [ id => 1, name => 'Mohsen', is_active => true, text => 'your text', age => 25 ], [ id => 2, name => 'Ali', is_active => true, text => 'your text', age => 20 ] ]; $result=EUserModel::newQuery()->saveMany($users);
有时,由于错误,某些项目可能无法保存在数据库中。您可以像下面这样进行检查
if($result->hasError()){
$notImportedItems=$result->getNotImportedItems();
}
$importedItems=$result->getImportedItems();
如果您想在出现任何错误时回滚事务,请将$withTransaction
参数设置为true
$result=EUserModel::newQuery()->saveMany(items:$users,withTransaction:true);
此操作将从数据库中删除导入的项目。
查找记录
$eArticleModel=new EArticleModel();
$result=$eArticleModel->find(2);
删除记录
$eArticleModel=new EArticleModel();
$result=$eArticleModel->find(2);
$result?->delete();
条件
等于
$eArticleModel
->where('id',2)
->orWhere('id',2)
->get();
不等于
$eArticleModel
->where('id','<>',2)
->orWhere('id','<>',10)
->get();
- 注意:不要在
text
字段上使用=
、<>
运算符,因为我们在这两个运算符中使用了term。在text
字段中,您需要使用like
或not like
运算符代替
大于
$eArticleModel->where('id','>',10)->orWhere('id','>=',20)->get();
小于
$eArticleModel->where('id','<',2)->orWhere('id',null)->first();
类似
$eArticleModel->where('name','like','foo')->orWhere('name','not like','foo2')->get();
whereTerm
有时您想在文本中搜索特定的短语。在这种情况下,您可以执行以下操作
$eArticleModel->whereTerm('name','foo')->orWhereTerm('name','<>','foo2')->get();
whereIn
$eArticleModel->whereIn('id',[1,2])->orWhereIn('age',[23,26])->first();
whereNotIn
$eArticleModel->whereNotIn('id',[1,2])->orWhereNotIn('id',[26,23])->get();
whereBetween
$eArticleModel->whereBetween('id,[1,2])->orWhereBetween('age',[26,27])->first();
whereNotBetween
$eArticleModel->whereNotBetween('id',[1,2])->orWhereNotBetween('id,'26,27])->get();
whereNull
$eArticleModel->whereNull('id')->orWhereNull('name')->first();
whereNotNull
$eArticleModel->whereNotNull('id')->orWhereNotNull()->first();
链式调用
$eArticleModel=new EArticleModel();
$eArticleModel
->where('name','<>','mohammad')
->orWhere('name,'komeil')
->whereNotIn('id,[1,2,3])
->where('name','like','value')
->whereBetween('id',[10,13])
->whereNotBetween('id',[1,2])
->whereTerm('name','foo')
->get();
模糊搜索
注意:模糊搜索仅适用于文本字段
$eArticleModel=new EArticleModel();
$eArticleModel
->whereFuzzy('name','mawebcoder',fuzziness:3)
->get();
您可以根据需要更改模糊度值
获取纯查询
$eArticleModel->where('id','like','foo')->dd();
更新记录
$eArticleModel=new EArticleModel();
$result=$eArticleModel->find(2);
$result?->update([
'name'=>'elastic',
//...
]);
批量更新
$eArticleModel=new EArticleModel();
$eArticleModel
->where('name','<>','mohammad')
->update([
'name'=>'elastic',
//...
]);
批量删除
$eArticleModel=new EArticleModel();
$eArticleModel
->where('name','<>','mohammad')
->delete();
获取一定数量的记录(限制)
$eArticleModel=new EArticleModel();
$eArticleModel
->where('name','<>','mohammad')
->take(10)
->get();
偏移量
$eArticleModel=new EArticleModel();
$eArticleModel
->where('name','<>','mohammad')
->take(10)
->offset(5)
->get();
选择
$eArticleModel=new EArticleModel();
$eArticleModel
->where('name','<>','mohammad')
->select('name,'age','id')
->get();
排序
$eArticleModel=new EArticleModel();
$eArticleModel
->where('name','<>','mohammad')
->select('name,'age')
->orderBy('age','desc')
->get();
- 注意:不要在
text
字段上使用orderBy
,因为文本不适合在Elasticsearch中进行排序操作。但如果您想强制对文本进行排序,请设置fielddata=true
$this->text(field:"description",fielddata:true)
通过添加上述行,您可以使用文本作为可排序的和在聚合中,但fielddata在索引时使用大量内存
获取特定字段的值
$name=$eArticleModel->name;
嵌套搜索
首先,我们需要在我们的迁移中定义object
类型
"category":{
"name":"elastic",
"id":2
}
$mapper->object('categories',[
'name'=>self::TYPE_STRING,
'id'=>self::TYPE_BIGINT
]);
$eArticleModel
->where('categories.name')->first();
如果您有如下所示的多维对象
"categories":[
{
"name":"elastic",
"id":2
},
{
"name":"mohammad",
"id":3
}
]
定义您的映射如下
$mapper->object('categories',[
'name'=>self::TYPE_STRING,
'id'=>self::TYPE_BIGINT
]);
$eArticleModel
->where('categories.name')->first();
按ID销毁
$eArticleModel->destroy([1,2,3]);
嵌套查询
为了创建复杂和嵌套的查询,您可以使用构建器的嵌套功能。您的查询嵌套没有限制
$model=Model::newQuery()
->where('name','john')
->where(function($model){
return $model->where('age',22)
->orWhere(function($model){
return $model->whereBetween('range',[1,10]);
})
})->orWhere(function($model){
return $model->where('color','red')
->orWhereIn('cars',['bmw','buggati'])
})->get()
请注意,您需要从闭包中返回查询,否则它将被忽略
chunk
为了更好地管理您的内存使用,您可以使用chunk方法
$model=Model::newQuery()
->where('name','mohammad')
->chunk(100,function(Collection $collection){
//code here
})
聚合
默认情况下,所有相关数据也将返回。如果您只想在结果中使用聚合,请使用take(0)
来防止在您的请求中过载数据
计数
$eArticleModel
->where('categories.name')
->orWhere('companies.title','like','foo')
->count();
桶
$eArticleModel
->bucket('languages','languages-count')
->get();
$aggregations=$eArticleModel['aggregations'];
默认情况下,桶方法返回最多2147483647
条记录,如果您想更改它
$eArticleModel
->bucket('languages','languages-count',300) //returns 300 records maximum
->get();
最小值
$model->min('year')->get()
最大值
$model->max('year')->get()
平均值
$model->avg('year')->get()
总和
$model->sum('year')->get()
唯一
有时您需要根据某个标准检索仅基于唯一记录
$model->where('category','elastic')->unique('name');
分组
为了根据某个标准对数据进行分组
$model->where('category','elastic')->groupby(field:'age',sortField:'category',direction:'desc');
分页
$eArticleModel
->where('categories.name')
->orWhere('companies.title','like','foo')
->paginate()
默认情况下,分页方法每页15个项目进行分页,但您可以进行更改
$eArticleModel
->where('categories.name')
->paginate(20)
结果将类似于以下内容
[
"data"=>[...],
'total_records' => 150,
'last_page' => 12,
'current_page' => 9,
'next_link' => localhost:9200?page=10,
'prev_link' => localhost:9200?page=8,
]
inRandomOrder
有时您需要从Elasticsearch中获取随机数据
$eArticleModel
->where('categories.name')
->inRandomOrder()
->take(10)
->get()
与文档交互
按名称删除索引
Elasticsearch::dropIndexByName($model->getIndexWithPrefix())
检查索引是否存在
Elasticsearch::hasIndex($model->getIndexWithPrefix())
获取所有索引
Elasticsearch::getAllIndexes()
按模型删除索引
Elasticsearch::setModel(EArticle::class)->dropModelIndex()
获取所有模型字段
Elasticsearch::setModel(EArticle::class)->getFields()
获取模型映射
Elasticsearch::setModel(EArticle::class)->getMappings()
即将推出
- 直方图
- 定义归一化和分词器
- 原始查询