掘金 后端 ( ) • 2024-05-09 09:52

theme: smartblue highlight: a11y-dark

安装

使用docker安装meilisearch

docker run -it --rm --name meilisearch -v $(pwd)/data:/data -p 7700:7700 getmeili/meilisearch:latest

使用

因为本人擅长的是PHP开发,所以本文示例都将使用PHPmeilisearch/meilisearch-php包演示

其他语言请参考官方文档 meilisearch

以下示例的数据结构为:

[
  {
    "id": 28,
    "name": "轻奢纯棉刺绣水洗四件套",
    "sub_name": "轻奢纯棉刺绣水洗四件套卖的真的好,爆款推荐(副标题)",
    "cate_id1": 3,
    "cate_id2": 26,
    "cate_id3": 30,
    "cate_id1_name": "男装女装",
    "cate_id2_name": "女装",
    "cate_id3_name": "T恤",
    "brand_id": 1001010,
    "brand_name": "品牌名称",
    "price": "111.00",
    "sales": 200,
    "tag_ids": [
      1,
      2
    ],
    "tags_name": [
      "新品",
      "爆款"
    ]
  },
  {
    "id": 29,
    "name": "秋冬保暖加厚澳洲羊毛被",
    "sub_name": "秋冬保暖加厚澳洲羊毛被卖的真的好,爆款推荐,超级合适(副标题)",
    "cate_id1": 2,
    "cate_id2": 18,
    "cate_id3": 23,
    "cate_id1_name": "礼品鲜花",
    "cate_id2_name": "鲜花",
    "cate_id3_name": "卡通花束",
    "brand_id": 1001002,
    "brand_name": "品牌名称22",
    "price": "36.00",
    "sales": 64,
    "tag_ids": [

    ],
    "tags_name": [

    ]
  },

初始准备

composer require meilisearch/meilisearch-php
composer require guzzlehttp/guzzle
composer require http-interop/http-factory-guzzle:^1.0

链接meilisearch:成功后我们就可以继续后续操作了

use Meilisearch\Client;

$client = new Client('http://127.0.0.1:7700',"API_KEY");

添加文档

$index = $client->index('goods');//goods是索引名称(index);可以类比为mysql的数据表
// $index->addDocumentsJson("json数组字符串");
//使用数组结构添加
$index->addDocuments([
    [
        "id" => 1,
        "name" => "名称1",
        ...
    ],
    [
        "id" => 2,
        "name" => "名称2",
        ...
    ]
]); 

修改index配置

添加完成后我们需要对索引(index)做一些设置,否则在查询或者排序时会出现错误

$settings = [
    //设置允许查询字段,不设置会出现( Message: Attribute `xxx` is not filterable. Available filterable) xxx字段不支持查询的错误
    'filterableAttributes' => [
        "name",
        "sub_name",
        "cate_id1",
        "cate_id2",
        "cate_id3",
        "brand_id",
        "tag_ids",
        "id",
    ],
    //设置允许排序的字段,不设置会出现(Message: Attribute `xxx` is not sortable. Available sortable attributes) xxx字段不支持排序的错误
    'sortableAttributes' => [
        'price',
        'sales',
    ],
    //设置排序优先级
    'rankingRules' => [
        'sort', //自定义sort优先
        'words', //关键词相关度优先
        'typo', //错词容忍度
        'proximity',
        'attribute',
        'exactness'
    ],   
];
$index = $index->index('goods');
$index->updateSettings($settings);

搜索



//假设我们要实现mysql的以下效果
//select * from goods where tag_ids in (1,2) and name like "%羊毛衫%" and cate_id1 = 1 ;
//或者
//select * from goods where (tag_ids =1 or tag_ids=2) and name like "%羊毛衫%" and cate_id1 = 1 ;
$filter=[
    ["cate_id1=1"],
    [
        ["tag_ids=1"],
        ["tag_ids=2"],
    ],
];//搜索条件

$query = "羊毛衫";//搜索关键字(模糊搜索字段)
$docs = $client->index('goods')
    ->search($query, [
        'filter' => $filter
    ]);

var_dump($docs->getHits()); //获取数据
限制返回字段

如果需要限制返回字段则增加attributesToRetrieve属性(顺序不影响查询相关度),类比mysql的 field字段

select id,name,sub_name from goods where (tag_ids =1 or tag_ids=2) and name like "%羊毛衫%" and cate_id1 = 1;


$client->index('goods')
    ->search($query, [
        'filter' => $filter,
        "attributesToRetrieve"=>[
            'id',
            'name',
            'sub_name',
        ],
    ]);

限制模糊查询的字段

$query字默认会在你配置项的所有字段进行搜索满足的,如果你只想某个或者某几个字段进行模糊搜索,应该使用attributesToSearchOn属性

例如以下示例就是 只在name和sub_name中模糊查询


$docs = $client->index('goods')
    ->search($query, [
        'filter' => $filter,
        "attributesToRetrieve"=>[
            'id',
            'name',
            'sub_name',
        ],
        "attributesToSearchOn"=>[
            'name',
            'sub_name',
        ],
    ]);
var_dump($docs->getHits()); //获取数据

分页

使用limit,offset分页

这种分页方式受限于index配置项(Settings object)中的pagination.maxTotalHits字段的长度

即:当offset偏移量大于了maxTotalHits,则会直接返回空结果,且无法获取当前条件查询下的总条数(totalHits),只能获取一个预估的数据条数(estimatedTotalHits)

$docs = $client->index('goods')
    ->search($query, [
        'filter' => $filter,
        "attributesToRetrieve"=>[
            'id',
            'name',
            'sub_name',
        ],
        "attributesToSearchOn"=>[
            'name',
            'sub_name',
        ],
        "limit"=>20,
        "offset"=>0,
    ]);

//$count = $docs->getTotalHits(); 无法获取

$count = $docs->getEstimatedTotalHits() //预估条数
使用hitsPerPage,page分页

这种模式下可以获取查询总条数(totalHits)


$docs = $client->index('goods')
    ->search($query, [
        'filter' => $filter,
        "attributesToRetrieve"=>[
            'id',
            'name',
            'sub_name',
        ],
        "attributesToSearchOn"=>[
            'name',
            'sub_name',
        ],
        "hitsPerPage" => 20, //分页条数
        "page" => 1, //第几页
    ]);
$count = $docs->getTotalHits(); 总的分页条数
var_dump($docs->getHits()); //获取数据

排序

排序字段在配置项设置sortableAttributes才可以排序

支持多字段排序 asc升序,desc降序

多个字段排序有优先级,第一个排序条件相同才会排序第二个排序条件,类比mysql的order by

如下示例类比mysql:

select * from goods where name like "%羊毛衫%" order by sales desc,price asc;


$sort = ["sales:desc", "price:asc"]

$docs = $client->index('goods')
    ->search("羊毛衫", [
        'sort' => $sort,
    ]);

完整查询示例

以下示例类比mysql:

select id,name,sub_name from goods where (tag_ids =1 or tag_ids=2) and name like "%羊毛衫%" and cate_id1 = 1 limit 20,offset 0;


//模糊搜索条件
$query ="羊毛衫";

//搜索条件
$filter=[
    ["cate_id1=1"],
    [
        ["tag_ids=1"],
        ["tag_ids=2"],
    ],
];

$sort = ["sales:desc", "price:asc"]

$docs = $client->index('goods')
    ->search($query, [
        'filter' => $filter, //搜索条件
        'sort' => $sort, //排序
        "hitsPerPage" => 20, //每页条数
        "page" => 1,//第几页
        "attributesToRetrieve"=>[ //限制返回数据
            'id',
            'name',
            'sub_name',
        ],
        "attributesToSearchOn"=>[ //限制模糊搜索的字段
            "name",
            "sub_name",
        ]
    ]);

$count = $docs->getTotalHits();
$data = $docs->getHits();