Elasticsearch实现Mysql的Like效果

在Mysql数据库中,模糊搜索通常使用LIKE关键字。然而,随着数据量的不断增加,Mysql在处理模糊搜索时可能面临性能瓶颈。因此,引入Elasticsearch(ES)作为搜索引擎,以提高搜索性能和用户体验成为一种合理的选择。

1、客户的诉求

在ES中,影响搜索结果的因素多种多样,包括分词器、Match搜索、Term搜索、组合搜索等。有些用户已经养成了在Mysql中使用LIKE进行模糊搜索的习惯。若ES返回的搜索结果不符合用户的预期,可能会引发抱怨,甚至认为系统存在Bug。

谁让客户是上帝,客户是金主爸爸呢,客户有诉求,我们就得安排上。下面我们就聊聊如何用ES实现Mysql的like模糊匹配效果。

如果对Elasticsearch不太熟悉的读者,建议先阅读我之前的文章:

5000字详说Elasticsearch入门

Springboot项目中使用Elasticsearch的RestClient

巧记Elasticsearch常用DSL语法

2、短语匹配match_phrase

2.1、定义

为实现模糊匹配的搜索效果,通常有两种方式,其中之一是match_phrase,先说说match_phrase。

match_phrase短语匹配会对检索内容进行分词,要求这些分词在被检索内容中全部存在,并且顺序必须一致。默认情况下,这些词必须是连续的。

2.2、实验

  • 场景1:创建一个mapping,采用默认分词器(即每个字都当做分词),然后插入两条数据。注意:被搜索的字段先采用text类型。
bash 复制代码
# 创建mapping,这里的customerName先使用text类型
PUT /search_test
{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "customerName": {
        "type": "text"
      }
    }
  },
  "settings": {
    "number_of_shards": 5,
    "number_of_replicas": 1
  }
}

# 插入2条数据
PUT /search_test/_create/1
{
  "id": "111",
  "customerName": "都是生产医院的人"
}

PUT /search_test/_create/2
{
  "id": "222",
  "customerName": "家电清洗"
}

# match_phrase短语匹配查询,可以查出结果
POST search_test/_search
{
  "from": 0,
  "size": 10,
  "query": {
    "bool": {
      "must": [
        {
          "match_phrase": {
            "customerName": "医院的"
          }
        }
      ]
    }
  }
}

以上操作结果显示可以查询到数据。如下图:

  • 场景2:创建一个mapping,采用默认分词器,然后插入两条数据。注意:被搜索的字段先采用keyword类型。
bash 复制代码
# 创建mapping,这里的customerName先使用text类型
PUT /search_test2
{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "customerName": {
        "type": "keyword"
      }
    }
  },
  "settings": {
    "number_of_shards": 5,
    "number_of_replicas": 1
  }
}

# 插入2条数据
PUT /search_test2/_create/1
{
  "id": "111",
  "customerName": "都是生产医院的人"
}

PUT /search_test2/_create/2
{
  "id": "222",
  "customerName": "家电清洗"
}

# match_phrase短语匹配查询,可以查出结果
POST search_test2/_search
{
  "from": 0,
  "size": 10,
  "query": {
    "bool": {
      "must": [
        {
          "match_phrase": {
            "customerName": "医院的"
          }
        }
      ]
    }
  }
}

以上操作结果显示查不到数据。如下图:

2.3、小结

match_phrase短语匹配适用于text类型的字段,实现了类似Mysql的like模糊匹配。然而,它并不适用于keyword类型的字段。

3、通配符匹配Wildcard

为实现模糊匹配的搜索效果,Wildcard通配符匹配是另一种常见的方式。下面我们详细介绍wildcard通配符查询。下面接着说Wildcard通配符查询。

3.1、定义

Wildcard Query 是使用通配符表达式进行查询匹配。Wildcard Query 支持两个通配符:

  • ?,使用 ? 来匹配任意字符。
  • *,使用 * 来匹配 0 或多个字符。

使用示例:

bash 复制代码
POST search_test/_search
{
  "query": {
    "wildcard": {
      "customerName": "*测试*"
    }
  }
}

3.2、实验

  • 场景1 :创建一个mapping,采用默认分词器,然后插入两条数据。注意:被搜索的字段先采用text类型。使用上文已经创建的索引search_test
bash 复制代码
# wildcard查询
POST search_test/_search
{
  "from": 0,
  "size": 10,
  "query": {
    "bool": {
      "must": [
        {
          "wildcard": {
            "customerName": {
              "value": "*医院的*"
            }
          }
        }
      ]
    }
  }
}

以上操作结果显示查不到数据,如下图:

注意:如果将DSL查询语句改成只查"医",就可以查到数据,这与分词器有关。默认分词器将每个字都切成分词。

bash 复制代码
# Wildcard查询
POST search_test/_search
{
  "from": 0,
  "size": 10,
  "query": {
    "bool": {
      "must": [
        {
          "wildcard": {
            "customerName": {
              "value": "*医*"
            }
          }
        }
      ]
    }
  }
}
  • 场景2 :创建一个mapping,采用默认分词器,然后插入两条数据。注意:被搜索的字段先采用keyword类型。使用上文已经创建的索引search_test2
bash 复制代码
POST search_test2/_search
{
  "from": 0,
  "size": 10,
  "query": {
    "bool": {
      "must": [
        {
          "wildcard": {
            "customerName": {
              "value": "*医院的*"
            }
          }
        }
      ]
    }
  }
}

以上操作结果显示可以查到数据,如下图:

3.3、小结

Wildcard通配符查询适用于keyword类型的字段,实现了类似Mysql的like模糊匹配。然而,它不太适用于text类型的字段。

4、选择分词器

上述实验中均使用了默认分词器的结果。接下来,我们尝试使用IK中文分词器进行实验。

4.1、实验

  • 创建一个名为search_test3的mapping,采用IK中文分词器,然后插入两条数据。注意:被搜索的字段先采用text类型。
bash 复制代码
PUT /search_test3
{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "customerName": {
        "type": "text",
        "analyzer": "ik_max_word",
        "search_analyzer": "ik_smart"
      }
    }
  },
  "settings": {
    "number_of_shards": 5,
    "number_of_replicas": 1
  }
}

PUT /search_test3/_create/1
{
  "id": "111",
  "customerName": "都是生产医院的人"
}

PUT /search_test3/_create/2
{
  "id": "222",
  "customerName": "家电清洗"
}
  • 执行搜索,比如搜索"医院的",无论是match_phrase还是wildcard两种方式都查不到数据。
bash 复制代码
POST search_test3/_search
{
  "from": 0,
  "size": 10,
  "query": {
    "bool": {
      "must": [
        {
          "match_phrase": {
            "customerName": "医院的"
          }
        }
      ]
    }
  }
}

POST search_test3/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "wildcard": {
            "customerName": {
              "value": "*医院的*"
            }
          }
        }
      ]
    }
  },
  "from": 0,
  "size": 20
}
  • 执行搜索,比如搜索"医院",match_phrase和wildcard两种方式都可以查到数据。
bash 复制代码
POST search_test3/_search
{
  "from": 0,
  "size": 10,
  "query": {
    "bool": {
      "must": [
        {
          "match_phrase": {
            "customerName": "医院"
          }
        }
      ]
    }
  }
}

POST search_test3/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "wildcard": {
            "customerName": {
              "value": "*医院*"
            }
          }
        }
      ]
    }
  },
  "from": 0,
  "size": 20
}

4.2、小结

无论是match_phrase还是wildcard两种方式,它们的效果与选择的分词器密切相关。因为两者都是对分词进行匹配,只有匹配到了分词,才能找到对应的文档。

如果搜索内容正好命中了对应的分词,就可以查询到数据。如果没有命中分词,则查不到。在遇到问题时,可以使用DSL查询查看ES的分词情况:

json 复制代码
POST _analyze
{  
    "analyzer": "ik_smart",
    "text": "院的人"  
}
POST _analyze
{  
    "analyzer": "ik_smart",
    "text": "医院的"  
}

POST _analyze
{  
    "analyzer": "ik_max_word",
    "text": "都是生产医院的人"  
}

5、总结

match_phrase和wildcard都能实现类似Mysql的like效果。然而,需要注意以下几点:

  • 如果要完全实现Mysql的like效果,最好使用默认分词器,即每个字都切成分词。
  • match_phrase短语匹配,适合于text类型的字段。
  • Wildcard通配符查询,适合于keyword类型的字段。

本篇完结!感谢你的阅读,欢迎点赞 关注 收藏 私信!!!

原文链接: mp.weixin.qq.com/s/pXGQsGs1l...

相关推荐
llp1110几秒前
基于java线程池和EasyExcel实现数据异步导入
java·开发语言
醇氧8 分钟前
【mybatis】 插件 idea-mybatis-generator
java·intellij-idea·mybatis
Eiceblue24 分钟前
Java 实现Excel转HTML、或HTML转Excel
java·html·excel·idea
forestsea2 小时前
【Elasticsearch】聚合分析:度量聚合
大数据·elasticsearch·搜索引擎
小石潭记丶2 小时前
ES设置证书和创建用户,kibana连接es
大数据·elasticsearch·jenkins
陈平安Java and C5 小时前
MyBatisPlus
java
秋野酱6 小时前
如何在 Spring Boot 中实现自定义属性
java·数据库·spring boot
安的列斯凯奇6 小时前
SpringBoot篇 单元测试 理论篇
spring boot·后端·单元测试
Bunny02126 小时前
SpringMVC笔记
java·redis·笔记
架构文摘JGWZ7 小时前
FastJson很快,有什么用?
后端·学习