laravel下安装composer插件
根据自己的版本进行安装
composer require elasticsearch/elasticsearch
框架下进行配置,env是在你目录里面的.env文件下的。
'elasticsearch' => [
// Elasticsearch 支持多台服务器负载均衡,因此这里是一个数组
'hosts' => explode(',', env('ELASTICSEARCH_HOST')),
'info'=>[
'medicine_pro'=>env('MEDICINE_PRO_INFO'),//这两个是我配置的不同索引
'medicine_store'=>env('MEDICINE_STORE_INFO'),
]
]
注意一个点:带账户密码的配置是这样的:在.env文件下的
ELASTICSEARCH_HOST=http://medicine:S7cxVXic@127.0.0.1:3307
配置完成之后我们来看一个类--自己写的
<?php
namespace App\Utils;
use Elasticsearch\ClientBuilder;
class Es
{
private $client;
const DISTANCE = "5000km";
// 构造函数
public function __construct()
{
$params =config('database.elasticsearch.hosts');
// array(
// '10.33.22.141:9200',
// );
$this->client = ClientBuilder::create()->setHosts($params)->build();
}
public function getClient() {
return $this->client;
}
// 创建索引
public function create_index($index_name = 'meitian', $properties = []) {
$params = [
'index' => $index_name
];
$exists = $this->client->indices()->exists($params);
if(!$exists) {
$params['body']['settings']['number_of_shards'] = 5;
$params['body']['settings']['number_of_replicas'] = 0;
if(!empty($properties)) {
$params['body']['mappings'] = [
'_source' => [
'enabled' => true
],
'properties' => $properties
];
}
echo 'create index: '.$index_name;
$response = $this->client->indices()->create($params);
return $response;
}
}
// 删除索引
public function delete_index($index_name = 'meitian') {
$params = [
'index' => $index_name
];
$response = $this->client->indices()->delete($params);
return $response;
}
// 添加文档
public function add_doc($id, $doc, $index_name = 'meitian') {
$params = [
'index' => $index_name,
'id' => $id,
'body' => $doc
];
$response = $this->client->index($params);
return $response;
}
// 批量添加文档
public function bulk_doc($docs, $index_name = 'meitian') {
$params = ['body' => []];
$res = 0;
foreach ($docs as $i => $item) {
if(!isset($item['id']) || empty($item['id'])) {
continue;
}
$params['body'][] = [
'index' => [
'_index' => $index_name,
'_id' => $item['id']
],
];
unset($item['id']);
$params['body'][] = $item;
if ($i % 1000 == 0) {
$responses = $this->client->bulk($params);
$params = ['body' => []];
unset($responses);
}
$res++;
}
if (!empty($params['body'])) {
$responses = $this->client->bulk($params);
}
return $res;
}
//批量添加文档:带经纬度定制所属字段
public function write($data , $index){
foreach ($data as $i => $item) {
$arr = $item->toESArray();
$arr['location'] = [
'lat' => $arr['lat'],
'lon' => $arr['lng']
];
unset($arr['lat']);
unset($arr['lng']);
$data[$i] = $arr;
}
$res = $this->bulk_doc($data, $index);
return $res;
}
// 判断文档存在
public function exists_doc($id, $index_name = 'meitian') {
$params = [
'index' => $index_name,
'id' => $id
];
$response = $this->client->exists($params);
return $response;
}
// 获取文档
public function get_doc($id, $index_name = 'meitian') {
$params = [
'index' => $index_name,
'id' => $id
];
$response = $this->client->get($params);
return $response;
}
// 更新文档
public function update_doc($id, $doc, $index_name = 'meitian') {
$params = [
'index' => $index_name,
'id' => $id,
'body' => [
'doc' => $doc
]
];
$response = $this->client->update($params);
return $response;
}
// 删除文档
public function delete_doc($id, $index_name = 'meitian') {
$params = [
'index' => $index_name,
'id' => $id
];
$response = $this->client->delete($params);
return $response;
}
//查看映射
public function get_mapping($index_name = "meitian") {
$params = [
'index' => $index_name,
];
$response = $this->client->indices()->getMapping($params);
return $response;
}
}
接下来我们进行创建需要的索引,索引名字,跟映射字段。
这个是我数据表的字段,你可以根据你自己的需求来,
你也可以把2张以上的表字段都这样弄。
geo_point这个类型是经纬度。下面写入数据的时候回说。
//创建索引,映射字段,可以在控制写,也可以在服务层写完调用这个。
public static function storeCrate (){
$store = [
'id' =>[
'type'=>'integer'
],
'title' =>[
'type'=>'keyword'
],
'mobile' =>[
'type'=>'keyword'
],
'location' => [
'type' => 'geo_point' //地理坐标
],
'status'=>[
'type' => 'integer',
],
'created_ad'=>[
'type' => 'keyword',
],
'updated_at'=>[
'type' => 'keyword',
],
];
$es = new Es();
$res = $es->create_index(config('database.elasticsearch.info.medicine_store'), $store);
return $res;
}
接下来我们看如何写入数据。--我们先来看批量写入---多表字段写入
//这个是多表的--调用的是上面的类。
//批量写入ES类里面这个方法:write 可以根据你自己业务写,如果不需要你可以删除,直接调用这个bulk_doc。这样你可以自己在model里面这样写。
//切记:$arr = $item->toESArray(); 这个是必须的。在模型里面。看下面的代码。
public static function Write(){
$es = new Es();
//添加门店数据
$pro = ArticleModel::query()
// 预加载 门店库存 和 商品基本库,门店表
->with(['goods'=>function($query){
$query->select('id','uniacid','pcate','ccate',
'tcate','status','title','thumb','goodssn','productsn','marketprice',
'createtime','updatetime','allcates',
'displayorder','common_name','approval',
'specifications','manufactor','type','subtitle','cates');
}])->with(['store'=>function($query){
$query->select('id','title','address','is_invoice','is_intra_city',
'is_express','is_store','lat','lng');
}])->select('id','store_id','goods_id','total','originalprice','price','status')
->get();
$res = $es->write($pro,config('elasticsearch.elasticsearch.info.medicine_pro'));
return $res;
}
model模型操作。这个是三张表的。单张的表的例子下面。
<?php
//这里我全部列出来。三张表操作的。
namespace App\Models;
use App\MyIndexConfigurator;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Laravel\Scout\Searchable;
class ArticleModel extends Model
{
//你的表
protected $table="mshop_store_product";
use Searchable;
public function goods()
{
return $this->hasOne(GoodsModel::class, 'id', 'goods_id');
}
public function store()
{
return $this->hasOne(StoreModel::class, 'id', 'store_id');
}
public function toESArray()
{
// 只取出需要的字段 门店商品库表
$arr = Arr::only($this->toArray(), [
'id',
'goods_id',
'store_id',
'uniacid',
'originalprice',
'price',
'total',
'status'
]);
//商品goods表的数据
$arr['uniacid'] = $this->goods->uniacid;//连锁id
$arr['pcate'] = $this->goods->pcate;//一级分类
$arr['ccate'] = $this->goods->ccate;//二级分类
$arr['tcate'] = $this->goods->tcate;//三级分类
$arr['goods_status'] = $this->goods->status;//商品状态
$arr['title'] = $this->goods->title;//商品标题
$arr['redundancy_title'] = $this->goods->common_name.' '.$this->goods->specifications.' '.$this->goods->manufactor;//冗余的商品标题
$arr['thumb'] = $this->goods->thumb;//商品图
$arr['goodssn'] = $this->goods->goodssn;//商品编号
$arr['productsn'] = $this->goods->productsn;//商品条码
$arr['marketprice'] = $this->goods->marketprice;//商品现价
$arr['createtime'] = $this->goods->createtime;//建立时间
$arr['updatetime'] = $this->goods->updatetime;//创建时间
$arr['allcates'] = ','.$this->goods->allcates.',';//商品分类集合
$arr['displayorder'] = $this->goods->displayorder;//排序
$arr['common_name'] = $this->goods->common_name;//通用名
$arr['approval'] = $this->goods->approval;//批准文号
$arr['specifications'] = $this->goods->specifications;//规格
$arr['manufactor'] = $this->goods->manufactor;//厂家
$arr['subtitle'] = $this->goods->subtitle;//子标题
$arr['type'] = $this->goods->goods_type;//类型
$arr['cates'] = ','.$this->goods->cates.',';//多重分类数据集
//门店详情表+经纬度
$arr['store_title'] = $this->store->title;
$arr['address'] = $this->store->address;
$arr['is_invoice'] = $this->store->is_invoice;
$arr['is_intra_city'] = $this->store->is_intra_city;
$arr['is_intra_city_self'] = $this->store->is_intra_city_self;//新增同城配送(店员自己送)
$arr['is_express'] = $this->store->is_express;
$arr['is_store'] = $this->store->is_store;
$arr['lat'] = $this->store->lat;
$arr['lng'] = $this->store->lng;
$arr['store_status'] = $this->store->status;//门店状态
$arr['num_total'] = $this->total;//多冗余字段
return $arr;
}
}
数量打的话,你可以写commands任务进行跑。
*接下来我们看单张表操作,这个很简单--我用commands给你演示
<?php
namespace App\Console\Commands;
use App\Models\StoreModel;
use App\Utils\Es;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
class ESstore extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'es:storeCreate';
/**
* The console command description.
*
* @var string
*/
protected $description = '导入门店数据';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
// 获取 Elasticsearch 对象
$es = new Es();
StoreModel::query()
// 使用 chunkById 避免一次性加载过多数据
->chunkById(10000, function ($products) use ($es) {
$this->info(sprintf('正在同步 ID 范围为 %s 至 %s 的商品', $products->first()->id, $products->last()->id));
// 遍历商品
foreach ($products as $i => $item) {
$arr = $item->toStore();
$arr['location'] = [
'lat' => $arr['lat'],
'lon' => $arr['lng']
];
unset($arr['lat']);
unset($arr['lng']);
$data[$i] = $arr;
}
try {
// 使用 bulk 方法批量创建
$res = $es->bulk_doc($data, config('database.elasticsearch.info.medicine_store'));
} catch (\Exception $e) {
$this->error($e->getMessage());
Log::info($e->getMessage());
}
},'id');
$this->info('同步完成');
Log::info('成功');
//插入redis
Redis::set('mshop:es:storeCreate',time());
}
}
这下面这个是在你model里面的
$arr = $item->toStore();
就这样的,是不是很简单
//导入门店的数据
public function toStore(){
$arr = Arr::only($this->toArray(), [
'id',
'thrid_id',
'uniacid',
'title',
'mobile',
'saletime',
'address',
'lng',
'lat',
'status',
'is_invoice',
'is_intra_city',
'is_intra_city_self',//新增同城配送(店员自己送)
'is_express',
'is_store',
'created_at',
'updated_at',
]);
return $arr;
}
都准备完成后,是不是要测试如何跑commands呢?执行下面命令
在你的项目目录下执行这个,会看到很多命令,然后你找一个:es:storeCreate 这个可以自己定义。
php artisan
然后找到执行这个:就可以跑了。
php artisan es:storeCreate
es可以跑百万的,你可以根据自己需求来。建议都是单张表,这样速度会快。
下一篇文章会讲如何update更新ES数据。shuai_664可以找到我,如果你有好的建议可以找我一起探讨。我也在摸索中。很多地方不懂。
网友评论