elasticsearch 进行模糊查询时,不同方式的差异性

众所周知,目前使用elasticsearch进行模糊搜索时,主要有2种方式

第一种:使用wildcard 关键字 + 未分词的字段进行搜索
第二种:使用match_phrase + 分词的方式进行搜索

对于这两种搜索,效率和性能上有什么区别呢?我们通过jmeter来压测下性能。
测试的服务器指标: 1C 2G
1、创建es的index
自定义一个分词器(分词器将一个文本分割成单个字符),并且一个字段(address)使用自定义分词器分词,一个字段(addressNoAnalysis)不分词,分词的字段用来校验match_phrase,不分词的字段用来校验wildcard。
如下

PUT /ngram_esapi
{
  "settings":{
    "analysis": {
      "analyzer": {
        "charSplit": {
          "type": "custom",
          "tokenizer": "my_ngram_tokenizer",
          "filter": [
            "lowercase"
          ],
          "char_filter": [
            "html_strip"
          ]
        }
      },
      "tokenizer": {
        "my_ngram_tokenizer": {
          "type": "nGram",
          "min_gram": "1",
          "max_gram": "1",
          "token_chars": [
            "letter",
            "digit",
            "punctuation"
          ]
        }
      }
    }
  },
  "mappings":{
    "ngram_person":{
      "properties":{
        "id": {
          "type": "long"
        },
        "age": {
          "type": "integer"
        },
        "name": {
          "type":"text",
          "analyzer":"charSplit"
        },
        "address": {
          "type":"text",
          "analyzer":"charSplit"
        },
        "addressNoAnalysis": {
          "type":"keyword"
        }
      }
    }
  }
}

2:随机生成500万个人员信息数据,插入到es中

for (int i = 0; i < 50000; i++) {
            threadPoolExecutor.execute(() -> {
                List<Person> persons = new ArrayList<>();
                for (int j = 0; j < 100; j++) {
                    Person person = new Person();
                    person.setName(ChineseNameGenerator.getInstance().generate());
                    person.setAge(ThreadLocalRandom.current().nextInt(100));
                    person.setAddress(ChineseAddressGenerator.getInstance().generate());
                    persons.add(person);
                }
                personService.createDatas(persons);
                try {
                    esService.createDatas(persons);
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            });
        }
        return "success";

3:编写接口,通过wildcard的 方式查询数据

    public List<Person> searchByWildcard(String keyword, String index, String type) throws Exception {

        SearchQuery searchQuery = new NativeSearchQuery(QueryBuilders.wildcardQuery("addressNoAnalysis", String.format("*%s*", keyword)));
        return elasticsearchTemplate.queryForList(searchQuery, Person.class);
    }

4:编写接口,通过match_phrase的方式查询数据

    public List<Person> searchByNgramSearch(String keyword, String index, String type) throws Exception {

        SearchQuery searchQuery = new NativeSearchQuery(new MatchPhraseQueryBuilder("address", keyword));
        List<Person> personList = elasticsearchTemplate.queryForList(searchQuery, Person.class);
        return personList;
    }

5:使用jmeter压测 wildcard的接口,并发数10个
在这里插入图片描述
服务器指标:
在这里插入图片描述

接口响应:
在这里插入图片描述

6:使用jmeter压测match_phrase的接口,并发个数10
在这里插入图片描述
服务器的指标:
在这里插入图片描述

接口响应:
在这里插入图片描述

结论:
可以看得出来使用第二种方式,无论是在性能上还是在服务器的压力上都明显优于第一种。

测试的代码已经上传到github上,感兴趣的同学可以自己去下载尝试

https://github.com/fanz1/esapi/tree/master

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值