Elasticsearch如何检索URL字段包含指定字符串的文档
Elasticsearch按URL包含字符串检索的最优方案
问题背景
现有ES索引存储html、url两个字段,初始映射如下:
{ "mappings": { "properties": { "html": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "url": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } } } } }
需求为查询url字段包含指定子串(如google.com)的文档,需同时匹配https://www.google.com、www.google.com/search两类URL。原有match_phrase查询无法稳定返回正确结果,原有查询代码:
query = { "query" : { "match_phrase" : { "url" : f"google.com" } } } response = elasticsearch.helpers.scan( es_client, index=my_index, doc_type="_doc", query=query )
原有方案失效原因
默认text字段使用standard分词器,会按标点、斜杠拆分URL内容,例如https://www.google.com会被拆分为https、www、google、com四个独立token。match_phrase要求查询词的分词顺序、位置完全匹配,google.com会被拆为google、com两个token,只有两个token相邻时才会命中,遇到带端口、多路径、查询参数的URL很容易漏匹配。
可选实现方案
方案1:零改动快速实现(无需重建索引)
直接针对不分词的url.keyword字段使用wildcard通配符查询,前后加*匹配任意前后缀,完全符合字符串包含的匹配逻辑:
query = { "query": { "wildcard": { "url.keyword": { "value": "*google.com*" } } } }
- 适用场景:数据量在百万级以下、临时查询、不想改动现有索引结构的场景
- 优缺点:无需改配置、无需重导数据,匹配准确率100%;但千万级以上数据量下,前后缀通配符查询性能较差,不适合高并发线上业务。
方案2:生产环境最优方案(推荐长期使用)
修改索引映射配置,为URL字段配置专用的n-gram分词器,兼顾匹配准确率和查询性能,需要重建索引:
- 新建索引,配置URL专用分词器和字段映射:
{ "settings": { "analysis": { "tokenizer": { "url_ngram_tokenizer": { "type": "ngram", "min_gram": 3, "max_gram": 15, "token_chars": ["letter", "digit", "punctuation", "symbol"] } }, "analyzer": { "url_ngram_analyzer": { "tokenizer": "url_ngram_tokenizer", "filter": ["lowercase"] } } } }, "mappings": { "properties": { "html": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "url": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 }, "match_substr": { "type": "text", "analyzer": "url_ngram_analyzer", "search_analyzer": "standard" } } } } } }
- 通过
reindex接口把存量数据导入新索引后,查询子串时直接用match查询url.match_substr字段即可:
query = { "query": { "match": { "url.match_substr": "google.com" } } }
- 适用场景:千万级以上数据量、线上高并发业务场景
- 优缺点:查询性能是wildcard方案的10~100倍,支持URL中特殊字符、端口、路径、参数的全场景匹配,不会漏判;仅需一次重建索引,额外存储开销极低。
兼容提示
ES 7.0及以上版本已经完全废弃索引类型(type)概念,helpers.scan调用中可以移除doc_type="_doc"参数,避免版本兼容报错。
内容的提问来源于stack exchange,提问作者Frederik
相关产品推荐
相关产品推荐

