安装php依赖包:
composer require hightman/xunsearch
composer require laravel/scout="7.2.1"
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
开始配置:
SCOUT_DRIVER=xunsearch
XUNSEARCH_HOST=192.168.91.158
SCOUT_PREFIX=
SCOUT_QUEUE=false
demo.php:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
use App\Services\XunSearchEngine;
class Demo extends Model
{
use Searchable;
protected $table='demo';
public $timestamps = true;
public function searchableIndexData()
{
$indexData = [
'id' => $this->id,
'title' => $this->title,
];
return $indexData;
}
public function searchableUsing()
{
$xs = new \XS(config_path('xunsearchini/demo.ini'));
return new XunSearchEngine($xs);
}
}
XunSearchEngine.php
namespace App\Services;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Log;
use Laravel\Scout\Builder;
class XunSearchEngine
{
protected $xs;
public function __construct(\XS $xs)
{
$this->xs = $xs;
}
/**
* 更新给定模型索引
*
* @param \Illuminate\Database\Eloquent\Collection $models
* @return void
* @throws \XSException
*/
public function update($models)
{
if ($models->isEmpty()) {
return;
}
// if ($this->usesSoftDelete($models->first()) && config('scout.soft_delete', false)) {
// $models->each->pushSoftDeleteMetadata();
// }
Log::info('Update Index');
$index = $this->xs->index;
$models->map(function ($model) use ($index) {
$array = $model->toSearchableArray();
if (empty($array)) {
return;
}
$doc = new \XSDocument;
// $data = [
// 'id' => $model->id,
// 'title' => $model->title,
// 'content' => $model->content,
// ];
$doc->setFields($model->searchableIndexData());
$index->update($doc);
});
$index->flushIndex();
}
/**
* 从索引中移除给定模型
*
* @param \Illuminate\Database\Eloquent\Collection $models
* @return void
* @throws \XSException
*/
public function delete($models)
{
$index = $this->xs->index;
$models->map(function ($model) use ($index) {
Log::info('Deleted:' . $model->getKey());
$index->del($model->getKey());
});
$index->flushIndex();
}
/**
* 通过迅搜引擎执行搜索
*
* @param \Laravel\Scout\Builder $builder
* @return mixed
*/
public function search(Builder $builder)
{
return $this->performSearch($builder, array_filter(['hitsPerPage' => $builder->limit]));
}
/**
* 分页实现
*
* @param \Laravel\Scout\Builder $builder
* @param int $perPage
* @param int $page
* @return mixed
*/
public function paginate(Builder $builder, $perPage, $page)
{
return $this->performSearch($builder, [
'hitsPerPage' => $perPage,
'page' => $page - 1,
]);
}
/**
* 返回给定搜索结果的主键
*
* @param mixed $results
* @return \Illuminate\Support\Collection
*/
public function mapIds($results)
{
return collect($results)
->pluck('id')->values();
}
/**
* 将搜索结果和模型实例映射起来
*
* @param Builder $builder
* @param \Illuminate\Database\Eloquent\Model $model
* @param mixed $results
* @return \Illuminate\Database\Eloquent\Collection
*/
public function map(Builder $builder, $results, $model)
{
if (count($results) === 0) {
return Collection::make();
}
$keys = collect($results)
->pluck('id')->values()->unique()->all();
$models = $model->getScoutModelsByIds($builder, $keys)->keyBy($model->getKeyName());
return Collection::make($results)->map(function ($hit) use ($model, $models) {
$key = $hit['id'];
if (isset($models[$key])) {
return $models[$key];
}
})->filter();
}
/**
* 返回搜索结果总数
*
* @param mixed $results
* @return int
*/
public function getTotalCount($results)
{
return ceil($this->xs->search->getLastCount() / 2);
}
// protected function usesSoftDelete($model)
// {
// return in_array(SoftDeletes::class, class_uses_recursive($model));
// }
// 执行搜索功能
protected function performSearch(Builder $builder, array $options = [])
{
$search = $this->xs->search;
if ($builder->callback) {
return call_user_func(
$builder->callback,
$search,
$builder->query,
$options
);
}
$search->setFuzzy()->setQuery($builder->query);
collect($builder->wheres)->map(function ($value, $key) use ($search) {
$search->addRange($key, $value, $value);
});
$offset = 0;
$perPage = $options['hitsPerPage'];
if (!empty($options['page'])) {
$offset = $perPage * $options['page'];
}
return $search->setLimit($perPage, $offset)->search();
}
/**
* 获取中文分词
* @param $text
* @return array
*/
public function getScwsWords($text)
{
$tokenizer = new \XSTokenizerScws();
return $tokenizer->getResult($text);
}
}
demo.ini:
project.name = demo
project.default_charset = utf-8
server.index = 192.168.91.158:8383
server.search = 192.168.91.158:8384
[id]
type = id
[title]
type = title
XunsearchController.php
namespace App\Http\Controllers;
use App\Models\Goods;
use App\Models\Student;
use App\Models\Demo;
class XunsearchController extends Controller
{
public function xundemo(){
//数据有更新和插入操作,会自动更新到xunsearch中
// $goods = new Goods();
// $goods->title = '终于成功了';
// $goods->content= '终于成功了';
// $goods->save();
// $student = new Student();
// $student->title = '终于成功了';
// $student->content= '终于成功了';
// $student->save();
// $demo = new Demo();
// $demo->title = '测试';
// $demo->content= '终于成功了';
// $demo->save();
$keyword = '测试';
$res = Demo::search($keyword)->paginate(20);
dd($res);
}
}