meilisearch全文检索elasticsearch的平替,应用于中小型项目足矣

摘要:本文主要介绍meilisearch的安装和简单使用。安装采用docker部署,案例与SpringBoot3结合,并展示了我们平常业务中会遇到的场景的使用案例。

meilisearchelasticsearch对比

1. 定位与核心目标

特性 MeiliSearch Elasticsearch
定位 轻量级、易用的全文搜索引擎,强调简单性和快速启动。 企业级搜索与分析引擎,支持复杂搜索、实时分析和大数据处理。
目标用户 开发者、初创团队、小型项目或内部工具。 中大型企业、需要复杂搜索和数据分析的场景(如日志、监控、电商)。

2. 架构与部署

特性 MeiliSearch Elasticsearch
架构 单节点为主,集群支持较简单。 分布式架构,天生支持分片(Shard)和副本(Replica),适合横向扩展。
部署复杂度 一键安装,依赖少,资源占用低。 需要 Java 环境,配置复杂,运维成本高。
扩展性 扩展性有限,适合中小规模数据。 支持动态扩缩容,适合海量数据和高并发场景。

3. 查询与功能

特性 MeiliSearch Elasticsearch
查询语法 简单 API,类似 RESTful,学习成本低。 复杂的 DSL(Domain-Specific Language),功能强大但学习曲线陡峭。
搜索模式 实时索引,支持模糊搜索、拼写纠正、同义词等基础功能。 支持聚合分析、地理搜索、模糊匹配、高亮等高级功能。
自定义功能 插件生态较少,扩展性有限。 丰富的插件生态(如中文分词器 IK、拼音分词),支持脚本和自定义分析器。

4. 性能与资源消耗

特性 MeiliSearch Elasticsearch
资源消耗 内存和 CPU 占用低,适合轻量级应用。 资源消耗较高,尤其是大数据量时需优化 JVM 和分片策略。
实时性 近实时(默认 1 秒刷新),适合一般场景。 近实时(默认 1 秒),支持更细粒度的刷新控制。
写入速度 较快,适合中小规模数据写入。 高吞吐写入,支持批量操作和复杂流水线处理。

安装

meilisearch安装

docker-compose.yml,挂载了数据出来

yaml 复制代码
services:
  meilisearch:
    image: getmeili/meilisearch:v1.14
    container_name: meilisearch
    environment:
      MEILI_MASTER_KEY: meilisearch_master
    ports:
      - 7700:7700
    volumes:
      - ./meili_data:/meili_data

环境变量说明

  • MEILI_MASTER_KEY: 相当于token,调用的秘钥,设计比较简单。

meilisearch-ui安装

该可视化工具只能在内网中使用,不能暴露到公网。

yaml 复制代码
services:
  meilisearch-ui:
    image: riccoxie/meilisearch-ui:lite
    container_name: meilisearch-ui
    ports:
      - 24900:24900

springboot集成使用

pom.xml

xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.meilisearch.sdk</groupId>
        <artifactId>meilisearch-java</artifactId>
        <version>0.14.4</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba.fastjson2</groupId>
        <artifactId>fastjson2</artifactId>
        <version>2.0.31</version>
    </dependency>
</dependencies>

application.yml

yaml 复制代码
meilisearch:
  host-url: http://192.168.137.131:7700
  master-key: meilisearch_master

MeilisearchProperties

typescript 复制代码
@Data
public class MeilisearchProperties {

    private String hostUrl;

    private String masterKey;

}

MeilisearchConfig

typescript 复制代码
@Configuration
public class MeilisearchConfig {

    @Bean
    @ConfigurationProperties(prefix = "meilisearch")
    public MeilisearchProperties meilisearchProperties(){
        return new MeilisearchProperties();
    }

    @Bean
    public Client meilisearchClient(MeilisearchProperties meilisearchProperties){
        return new Client(new Config(meilisearchProperties.getHostUrl(), meilisearchProperties.getMasterKey()));
    }

}

Goods

定义的存储实体

vbnet 复制代码
@Data
public class Goods {

    private Long id;

    private String name;

    private String desc;

    private String score;

    private Long paid;

}

GoodsService

typescript 复制代码
@Service
public class GoodsService {

    @Autowired
    private Client client;

    /**
     * 新增或编辑内容
     * @param goodsList
     */
    public void add(List<Goods> goodsList){
        Index index = client.index("goods");
        index.addDocuments(JSON.toJSONString(goodsList));
    }

    /**
     * 简单搜索
     * @param search
     * @return
     */
    public SearchResult search(String search){
        Index index = client.index("goods");
        return index.search(search);
    }

    /**
     * 高亮搜索
     * @param search
     * @return
     */
    public Searchable search2(String search){
        SearchRequest searchRequest = new SearchRequest(search);
        searchRequest.setShowMatchesPosition(true);
        searchRequest.setAttributesToHighlight(new String[] {"name"});
        Index index = client.index("goods");
        return index.search(searchRequest);
    }

    /**
     * 带过滤条件的搜索
     * @param search
     * @return
     */
    public Searchable search3(String search){
        SearchRequest searchRequest = new SearchRequest(search);
        searchRequest.setShowMatchesPosition(true);
        searchRequest.setAttributesToHighlight(new String[] {"name"});
        searchRequest.setFilter(new String[] {"id > 1 AND name = Action"});
        Index index = client.index("goods");
        index.updateFilterableAttributesSettings(new String[]
                {
                        "id",
                        "name"
                });
        return index.search(searchRequest);
    }

    /**
     * 自定义评分搜索
     * @param search
     * @return
     */
    public Searchable search4(String search){
        Index index = client.index("goods");
        index.updateSortableAttributesSettings(new String[] {"score"});
        index.updateRankingRulesSettings(new String[]{
                "paid:desc",
                "words",
                "typo",
                "proximity",
                "attribute",
                "sort",
                "exactness"}
        );
        SearchRequest searchRequest = new SearchRequest(search);
        searchRequest.setShowRankingScore(true);
        //searchRequest.setSort(new String[]{"score:desc"});
        return index.search(searchRequest);
    }
}

GoodsController

入口控制器

typescript 复制代码
@RestController
@RequestMapping(value = "goods")
public class GoodsController {

    @Autowired
    public GoodsService goodsService;
    @Autowired
    private Client client;

    @GetMapping("createIndex")
    public Object createIndex(String index){
        client.createIndex(index, "id");
        client.getIndex(index).updateFilterableAttributesSettings(new String[]{ "id", "name", "age"});
        client.getIndex(index).updateRankingRulesSettings(new String[] {});
        return "success";
    }

    @PostMapping(value = "add")
    public Object add(@RequestBody List<Goods> goodsList){
        goodsService.add(goodsList);
        return "success";
    }

    @GetMapping(value = "search")
    public Object search(String search) {
        return goodsService.search(search);
    }

    @GetMapping(value = "search2")
    public Object search2(String search) {
        return goodsService.search2(search);
    }

    @GetMapping(value = "search3")
    public Object search3(String search) {
        return goodsService.search3(search);
    }

    @GetMapping(value = "search4")
    public Object search4(String search) {
        return goodsService.search4(search);
    }

}

实际场景案例

电商搜索案例

电商搜索一般都有价格区间查询,价格排序,销量排序,所以我们就要把评分标准的判断sort提前,一般提到第一个。

  • 配置
arduino 复制代码
Index index = client.index("goods");
        index.updateSortableAttributesSettings(new String[] {"score"});
        index.updateRankingRulesSettings(new String[]{
                "sort",
                "words",
                "typo",
                "proximity",
                "attribute",
                "exactness"}
        );
  • 查询
ini 复制代码
SearchRequest searchRequest = new SearchRequest(search);
        searchRequest.setShowRankingScore(true);
        searchRequest.setSort(new String[]{"score:desc"});
        return index.search(searchRequest);

知识库搜索案例

就默认的排序即可,完全按照权重数据来排序

相关推荐
Ray6610 分钟前
store vs docValues vs index
后端
像污秽一样37 分钟前
软件开发新技术复习
java·spring boot·后端·rabbitmq·cloud
Y_3_71 小时前
Netty实战:从核心组件到多协议实现(超详细注释,udp,tcp,websocket,http完整demo)
linux·运维·后端·ubuntu·netty
小雄Ya1 小时前
Auth01|常见三种登录认证机制
后端·go
颛顼1 小时前
【源码分析】:从零拆解bs_worker的3层核心架构
后端·搜索引擎
yihuiComeOn1 小时前
【大数据高并发核心场景实战】 - 数据持久化之冷热分离
java·后端
Kookoos1 小时前
ABP VNext + MongoDB 数据存储:多模型支持与 NoSQL 扩展
后端·mongodb·c#·.net·abp vnext
加瓦点灯2 小时前
深挖 JVM 关闭钩子与 Signal 机制:优雅停机背后的秘密
后端
程序小武2 小时前
Python面向对象编程-类方法与静态方法
后端