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);

知识库搜索案例

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

相关推荐
程序员葵安1 小时前
【苍穹外卖项目】Day05
spring boot·后端
Code blocks6 小时前
关于“LoggerFactory is not a Logback LoggerContext but Logback is on ......“的解决方案
java·spring boot·后端
04Koi.9 小时前
八股训练--Spring
java·后端·spring
TMT星球10 小时前
好未来披露2026财年Q1财报:净利润3128万美元,同比大增174%
搜索引擎
Livingbody11 小时前
【心理咨询师数字孪生对话数据集】标准化为 ShareGPT OpenAI 格式
后端
AQin101212 小时前
IP 🆚 MAC,你分得清吗?
后端·网络协议
天涯学馆13 小时前
Solidity 中的高级模式匹配:提升代码的可读性和可维护性
后端·区块链·solidity
郝学胜-神的一滴13 小时前
Spring Boot Actuator 保姆级教程
java·开发语言·spring boot·后端·程序人生
剪刀石头布啊13 小时前
数据口径
前端·后端·程序员
剪刀石头布啊14 小时前
http状态码大全
前端·后端·程序员