背景:在业务项目中需对车牌号码使用模糊检索,在数据量不大(5000万以内)的情况下使用Term-level queries中Wildcard Query 和 Fuzzy Query查询即可满足业务要求,业务要求3秒内返回响应结果。
但随着项目规模越来越大,数据量是线性上升,当数据量到达10亿时,发现使用上面的模糊查询方式已存在性能瓶颈(查询响应慢 & 偶尔Elasticsearch还会抛出内存溢出错误)。
基于此,有必要对Elasticsearch的模糊查询进行性能优化。
https://github.com/memoryFuhao/elasticsearch_client (打个广告 以上链接是本人开发的一个es客户端工具,支持es大部分 CRUD操作 分页、分组、嵌套分组、and or ···,有需要的朋友可以pull代码直接使用)
相关知识点(可先看下面的优化方案后在看此项相关基础知识):
查询分类》Term-level queries 、 Full text queries
查询分类介绍》https://www.jianshu.com/p/56a1db3a61d5
分词器选择》NGram Tokenizer(本次选用的分词器)
分词器详细介绍》https://www.gwygd.com/OwRyr1rxg.html
分析器介绍》分析器是专门处理分词的组件,Analyzer(分析器) 由三部分组成
Character Filters (针对原始文本处理,例如去除 html)
Tokenizer(按照规则切分为单词)
Token Filter (将切分的单词进行加工,小写,删除 stopwords,增加同义语)
优化方案参考下面两步(在10亿数据量情况下将Elasticsearch模糊查询性能从10S优化到秒级内响应):
1.创建索引时,自定义分词器,并对需要模糊查询的字段指定自定义分词器。
{
"settings": {
"index": {
"analysis": {
"tokenizer": {
"my_tokenizer": { // 自定义分词器,名称自定义
"token_chars": ["letter","digit"], // 指定以字母和数字作为字符进行拆分
"min_gram": "1", // 拆分最小长度
"type": "ngram", // 选用连词分词器作为基础
"max_gram": "10" // 拆分最大长度
}
},
"analyzer": {
"my_analyzer": {"tokenizer": "my_tokenizer"} // 自定义分析器,以自定义分词器为基础
}
}
}
},
"mappings": {
"data": {
"properties": {
"plateno": {
"analyzer": "my_analyzer", // 使用自定义分析器,在入库时即对数据进行分词操作,以数据存储空间换数据检索时间。
"type": "text",
"fields": {
"keyword": {"type": "keyword"}
}
}
}
}
}
}
2.查询时指定分析器为Keyword Analyzer。
curl -X GET "http://172.16.1.18:9200/vlpr_result_temp/_search?pretty" -H "Authorization: Basic ZWxhc3RpYzoxMjM0NTY=" -H 'Content-Type: application/json' -d'
{
"query": {
"match": {
"plateno": "7557",
"analyzer": "keyword" // 查询时候指定keyword分析器,目的:该分析器默认不进行分词,若不指定则按照字段默认的分析器进行分词,会降低查询性能和模糊匹配的准确度
}
}
}
'
总结:此次优化核心就是以空间换时间的操作,自定义分析器目的就是将存储数据按自定义的格式切分然后构建索引进行存储,会增加一定的存储空间;查询时指定keyword分析器的目的是为了减少Elasticsearch进行的搜索次数。 该篇博客适用于对Elasticsearch有一定使用经验的人士,对刚接触的人员可能难以理解,请自行百度了解相关知识点。