Laravel+Swoole+PHP-ml 实现根据经纬度返回对应城市 
                                                    
                        
                    
                    
  
                    
                    今天不是很忙,写个小东西分享给大家。
https://github.com/Aquarmini/laravel-phpml...
首先我们新建个项目
composer create laravel/laravel
composer require swooletw/laravel-swoole
composer require php-ai/php-ml
然后我们把配置生成一下,选择 SwooleTW\Http\LaravelServiceProvider
php artisan vendor:publish
接下来生成一下模型
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
/**
 * @property $oid
 * @property $area_name
 * @property $level
 * @property $parent_oid
 * @property $province_oid
 * @property $city_oid
 * @property $county_oid
 * @property $area_code
 * @property $simple_name
 * @property $lon
 * @property $lat
 * @property $zip_code
 * @property $whole_name
 * @property $whole_oid
 * @property $pre_pin_yin
 * @property $pin_yin
 * @property $simple_py
 * @property $remark
 * @property $version
 */
class PoiDistricts extends Model
{
    /**
     * The primary key for the model.
     *
     * @var string
     */
    public $primaryKey = 'oid';
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'poi_districts';
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['oid', 'area_name', 'level', 'parent_oid', 'province_oid', 'city_oid', 'county_oid', 'area_code', 'simple_name', 'lon', 'lat', 'zip_code', 'whole_name', 'whole_oid', 'pre_pin_yin', 'pin_yin', 'simple_py', 'remark', 'version'];
    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = ['oid' => 'integer', 'level' => 'integer', 'parent_oid' => 'integer', 'province_oid' => 'integer', 'city_oid' => 'integer', 'county_oid' => 'integer', 'lon' => 'float', 'lat' => 'float', 'version' => 'float'];
}
接下来我们写一个生成训练用数据的脚本。
<?php
namespace App\Console\Commands;
use App\PoiDistricts;
use Illuminate\Console\Command;
use Swoole\Runtime;
class PoiDistrictCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'ml:districts';
    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Generate samples and labels.';
    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }
    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        Runtime::enableCoroutine(false);
        $arrays = PoiDistricts::query()->where('level', 5)->get(['parent_oid', 'lon', 'lat']);
        $input = [];
        $result = [];
        foreach ($arrays as $item) {
            if (is_numeric($item['lon']) && is_numeric($item['lat'])) {
                $input[] = [
                    $item['lon'],
                    $item['lat']
                ];
                $result[] = $item['parent_oid'];
            }
        }
        file_put_contents(base_path('storage/samples'), serialize($input));
        file_put_contents(base_path('storage/labels'), serialize($result));
    }
}
接下来生成我们的训练数据
php artisan ml:districts
这时,就可以在storage目录下看到我们的训练数据 samples 和 labels 了。
继续我们的开发,后面就是编写路由和控制器
<?php
# Route::get('/', 'IndexController@index');
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class IndexController extends Controller
{
    public function index(Request $request)
    {
        $lon = $request->input('lon');
        $lat = $request->input('lat');
        // TODO: 查询对应数据
        return [];
    }
}
接下来完善我们用于训练数据的类
<?php
namespace App;
use Illuminate\Container\Container;
use Phpml\Classification\KNearestNeighbors;
class PoiDistrictService
{
    /**
     * @var KNearestNeighbors
     */
    protected $classifier;
    protected $container;
    public function __construct(Container $container)
    {
        $this->container = $container;
        $samples = unserialize(file_get_contents(base_path('storage/samples')));
        $labels = unserialize(file_get_contents(base_path('storage/labels')));
        $this->classifier = new KNearestNeighbors();
        $this->classifier->train($samples, $labels);
    }
    /**
     * @return KNearestNeighbors
     */
    public function getClassifier(): KNearestNeighbors
    {
        return $this->classifier;
    }
}
然后在AppServiceProvider中注册一下我们的训练库
<?php
namespace App\Providers;
use App\PoiDistrictService;
use Illuminate\Container\Container;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        Container::getInstance()->singleton(PoiDistrictService::class, function ($app) {
            return new PoiDistrictService($app);
        });
    }
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
    }
}
接下来就简单了,重写我们之前的控制器。
<?php
namespace App\Http\Controllers;
use App\PoiDistricts;
use App\PoiDistrictService;
use Illuminate\Http\Request;
class IndexController extends Controller
{
    public function index(Request $request)
    {
        $lon = $request->input('lon');
        $lat = $request->input('lat');
        // 查询对应数据
        $client = app()->get(PoiDistrictService::class)->getClassifier();
        $id = $client->predict([$lon, $lat]);
        $model = PoiDistricts::query()->where('oid', $id)->first();
        return $model->toArray();
    }
}
最后就是测试一下了
php artisan swoole:http start
curl http://127.0.0.1:1215/?lon=119.2716979980&lat=36.7608912496
{
    "oid": 1782,
    "area_name": "奎文区",
    "level": 4,
    "parent_oid": 177,
    "province_oid": 6,
    "city_oid": 177,
    "county_oid": 1782,
    "area_code": "0536",
    "simple_name": "奎文",
    "lon": 119.12532,
    "lat": 36.70723,
    "zip_code": "261000",
    "whole_name": "中国,山东省,潍坊市,奎文区",
    "whole_oid": "1,6,177,1782",
    "pre_pin_yin": "K",
    "pin_yin": "Kuiwen",
    "simple_py": "KW",
    "remark": "",
    "version": 1
}
响应时间100ms左右,其实也还不错。
并发场景下还是和专门为swoole开发的框架有一定差距。

不过差距也不太大咯,反正也没人会在PHP里搞这个吧。。
本作品采用《CC 协议》,转载必须注明作者和本文链接
                      本帖由系统于 6年前 自动加精
            
                
          
            
          
          
                关于 LearnKu
              
                    
                    
                    
 
推荐文章: