Elasticsearch 完整格式的 URL 进行分词,有什么好的解决方案吗?

1、问题描述

我想对完整格式的 url 进行分词,请问有什么好的解决方案吗?

比如:https://www.abc.com/any/path?param_1=so+me\&param-2=other#title

看了官方的分词器,感觉没啥合适的?

预处理的话,又不知道该怎么处理更合适?

因为我们的数据量比较大,不太想用 pattern,感觉集群的压力会升高?

我看这个分词器会把识别的 url 当作一个token,但我想实现的是,对 url 尽可能保证精准的拆分。

2、URL 有哪些分词器?

昨天跟 Elastic 官方布道师刘晓国老师一起直播讲 Elastic 认证的时候,刘老师提到:"不是每个人都把每个语法知识点都记得非常清楚,也没有必要。用到的时候查官方文档就可以"。

是这个道理,URL 自定义分词并没有那么常见。那咱们看看官方支持哪些吧?都拎出来用一下,不行就再想办法。

整体看下来直接和 URL 直接相关的就一个:UAX URL email

间接相关的还有:path_hierarchy 分词、char_group 分词(可配置分割字符)。

无法之法就是挨个试一遍!

3、URL 分析器逐个验证

3.1 UAX URL email 分词

3.1.1 UAX URL email 分词功能

UAX URL email 分词器专门用于处理包含 URL 和电子邮件地址的文本。

它不仅能够正确识别和分词 URL,还可以处理电子邮件地址,并将其分割为有意义的部分。

3.1.2 UAX URL email 分词用途

UAX URL email 分词器适用于文本中包含电子邮件或 URL 的场景,确保这些特殊字符不会被简单地分割成无意义的碎片。

3.1.3 UAX URL email 分词配置示例及验证

go 复制代码
POST _analyze
{
  "tokenizer": "uax_url_email",
  "text": "Email me at john.smith@global-international.com"
}

分词后的结果是:

go 复制代码
{
  "tokens": [
    {
      "token": "Email",
      "start_offset": 0,
      "end_offset": 5,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "me",
      "start_offset": 6,
      "end_offset": 8,
      "type": "<ALPHANUM>",
      "position": 1
    },
    {
      "token": "at",
      "start_offset": 9,
      "end_offset": 11,
      "type": "<ALPHANUM>",
      "position": 2
    },
    {
      "token": "john.smith@global-international.com",
      "start_offset": 12,
      "end_offset": 47,
      "type": "<EMAIL>",
      "position": 3
    }
  ]
}

从执行结果看出,单词分词,URL 单独作为一个 token 词项单元。

这时候能想到,如果用这个分词器处理 https://www.abc.com/any/path?param_1=so+me\&param-2=other#title 的时候,不会做切分。

真实验证如下,和我们预期一致。

如果对参数 max_token_length 稍加调整,

go 复制代码
PUT my-index-000001
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "tokenizer": "my_tokenizer"
        }
      },
      "tokenizer": {
        "my_tokenizer": {
          "type": "uax_url_email",
          "max_token_length": 5
        }
      }
    }
  }
}

POST my-index-000001/_analyze
{
  "analyzer": "my_analyzer",
  "text": "john.smith@global-international.com"
}

执行一下:

go 复制代码
{
  "tokens": [
    {
      "token": "john",
      "start_offset": 0,
      "end_offset": 4,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "smith",
      "start_offset": 5,
      "end_offset": 10,
      "type": "<ALPHANUM>",
      "position": 1
    },
    {
      "token": "globa",
      "start_offset": 11,
      "end_offset": 16,
      "type": "<ALPHANUM>",
      "position": 2
    },
    {
      "token": "l",
      "start_offset": 16,
      "end_offset": 17,
      "type": "<ALPHANUM>",
      "position": 3
    },
    {
      "token": "inter",
      "start_offset": 18,
      "end_offset": 23,
      "type": "<ALPHANUM>",
      "position": 4
    },
    {
      "token": "natio",
      "start_offset": 23,
      "end_offset": 28,
      "type": "<ALPHANUM>",
      "position": 5
    },
    {
      "token": "nal.c",
      "start_offset": 28,
      "end_offset": 33,
      "type": "<ALPHANUM>",
      "position": 6
    },
    {
      "token": "om",
      "start_offset": 33,
      "end_offset": 35,
      "type": "<ALPHANUM>",
      "position": 7
    }
  ]
}

咋一看,好像是我们想要的结果。仔细一看,不如咋一看。仔细一看,出了问题?!

在上述操作中使用了 uax_url_email 分词器,这个分词器专门处理 URL 和电子邮件地址,并设置了 max_token_length 为 5,这意味着每个分词的最大长度为 5 个字符(这很关键)。

在分析文本 "john.smith@global-international.com" 时,分词器对电子邮件地址进行了分词,结果如下:

"john" 和 "smith" 被分别作为单独的 token,因为它们是以 . 分隔的部分,并且每部分长度在 5 个字符以内。

后面的域名部分 global-international.com 被分割成多个 token,每个 token 长度不超过 5 个字符:"globa"、"inter"、"natio" 这些 token 依次从域名中提取出来。

由于 max_token_length 被限制为 5,长的单词被截断,如 global 被拆分为 "globa" 和 "l"。

最终结果是,整个电子邮件地址被分成 8 个 token,每个 token 的长度 不超过 5 个字符

这个分词器对于处理电子邮件地址和 URL 等结构化文本非常有用,同时通过设置 max_token_length 可以控制分词的粒度。

但,截断的处理显然不符合预期。

3.2 path_hierarchy 分词

3.2.1 path_hierarchy 分词功能

path_hierarchy 分词器主要用于处理文件路径、URL 或其他层次结构的字符串。它会逐级分割字符串,并生成所有可能的路径层次。

3.2.2 path_hierarchy 分词用途

适合用于处理文件系统路径、URL 层次结构等,特别是需要检索某一特定层级或更高层级时非常有用。

3.2.3 path_hierarchy 分词使用举例

go 复制代码
POST _analyze
{
  "tokenizer": "path_hierarchy",
  "text": "https://www.abc.com/any/path?param_1=so+me&param-2=other#title"
}

返回结果如下:

go 复制代码
{
  "tokens": [
    {
      "token": "https:",
      "start_offset": 0,
      "end_offset": 6,
      "type": "word",
      "position": 0
    },
    {
      "token": "https:/",
      "start_offset": 0,
      "end_offset": 7,
      "type": "word",
      "position": 0
    },
    {
      "token": "https://www.abc.com",
      "start_offset": 0,
      "end_offset": 19,
      "type": "word",
      "position": 0
    },
    {
      "token": "https://www.abc.com/any",
      "start_offset": 0,
      "end_offset": 23,
      "type": "word",
      "position": 0
    },
    {
      "token": "https://www.abc.com/any/path?param_1=so+me&param-2=other#title",
      "start_offset": 0,
      "end_offset": 62,
      "type": "word",
      "position": 0
    }
  ]
}

从上面结果可以看出:path_hierarchy 分词器从最顶层(协议部分)开始,一步步解析出路径中的不同层次,生成多个分层级的 token,每个 token 表示 URL 的某个级别。

这个分词器会对路径中的每一层做分解,但它并不会解析 URL 中的查询参数、片段等部分。

这种分词方式对于处理层次化的 URL 非常有用,适合需要检索某一级 URL 层次的场景。例如,用户可以搜索整个网站、某个目录或具体路径。

3.3 char_group 分词(可配置分割字符)

3.3.1 char_group 分词功能

char_group 分词器允许用户定义分割字符集,例如可以自定义将 . 或 / 作为分割符,从而实现对 URL 进行特定模式的分词。

3.3.2 char_group 分词器用途

适合需要灵活处理 URL 或路径的场景,用户可以根据具体需求配置分割字符。

要对完整格式的 URL 进行精准的分词,同时又要在大数据量的情况下避免增加集群压力,建议使用 char_group 分词器。

char_group 分词器效率高,适合处理大量数据,因为它不使用正则表达式,不会像 开篇提到的 pattern 正则分词器那样消耗大量资源。

3.3.3 char_group 分词使用范例

我们可以配置 char_group 分词器,根据 URL 中常见的分隔符进行分词,例如 ** :, /, ?, &, =, +, #, -, _, . ** 等。

这些字符可以帮助你将 URL 拆分成有意义的部分,如协议、域名、路径、查询参数等。

详见官方文档;

https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-chargroup-tokenizer.html

以下是具体的实现方案:

go 复制代码
PUT your_index
{
  "settings": {
    "analysis": {
      "tokenizer": {
        "url_tokenizer": {
          "type": "char_group",
          "tokenize_on_chars": [
            "whitespace",
            ":",
            "/",
            "?",
            "&",
            "=",
            "+",
            "#",
            "-",
            "_",
            "."
          ]
        }
      },
      "analyzer": {
        "url_analyzer": {
          "tokenizer": "url_tokenizer",
          "filter": ["lowercase"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "url": {
        "type": "text",
        "analyzer": "url_analyzer"
      }
    }
  }
}

上述定义解读如下:

  • url_tokenizer:

使用 char_group 分词器,根据指定的字符进行分词。

  • tokenize_on_chars:

定义了分词的字符集,包括 URL 中常见的分隔符。

  • url_analyzer:

使用 url_tokenizer 作为分词器,并添加了 lowercase 过滤器,将所有词元转换为小写。

开篇问题测试如下:

go 复制代码
GET your_index/_analyze
{
  "analyzer": "url_analyzer",
  "text": "https://www.abc.com/any/path?param_1=so+me&param-2=other#title"
}

返回结果:

go 复制代码
{
  "tokens": [
    {
      "token": "https",
      "start_offset": 0,
      "end_offset": 5,
      "type": "word",
      "position": 0
    },
    {
      "token": "www",
      "start_offset": 8,
      "end_offset": 11,
      "type": "word",
      "position": 1
    },
    {
      "token": "abc",
      "start_offset": 12,
      "end_offset": 15,
      "type": "word",
      "position": 2
    },
    {
      "token": "com",
      "start_offset": 16,
      "end_offset": 19,
      "type": "word",
      "position": 3
    },
    {
      "token": "any",
      "start_offset": 20,
      "end_offset": 23,
      "type": "word",
      "position": 4
    },
    {
      "token": "path",
      "start_offset": 24,
      "end_offset": 28,
      "type": "word",
      "position": 5
    },
    {
      "token": "param",
      "start_offset": 29,
      "end_offset": 34,
      "type": "word",
      "position": 6
    },
    {
      "token": "1",
      "start_offset": 35,
      "end_offset": 36,
      "type": "word",
      "position": 7
    },
    {
      "token": "so",
      "start_offset": 37,
      "end_offset": 39,
      "type": "word",
      "position": 8
    },
    {
      "token": "me",
      "start_offset": 40,
      "end_offset": 42,
      "type": "word",
      "position": 9
    },
    {
      "token": "param",
      "start_offset": 43,
      "end_offset": 48,
      "type": "word",
      "position": 10
    },
    {
      "token": "2",
      "start_offset": 49,
      "end_offset": 50,
      "type": "word",
      "position": 11
    },
    {
      "token": "other",
      "start_offset": 51,
      "end_offset": 56,
      "type": "word",
      "position": 12
    },
    {
      "token": "title",
      "start_offset": 57,
      "end_offset": 62,
      "type": "word",
      "position": 13
    }
  ]
}

从结果看,基本符合预期。

4、char_group 优势及注意事项

4.1 char_group 优势

可总结为三条:高效、精准、可扩展。

高效:char_group 分词器不使用正则表达式,性能优于 pattern 分词器,适合大数据量场景。

精准:根据指定的字符进行分词,能够精确地拆分 URL 的各个组成部分。

可扩展:可以根据需要调整 tokenize_on_chars 中的字符,定制分词规则。

4.2 char_group 注意事项

如果需要更复杂的分词逻辑,例如基于特定模式的拆分,可以考虑使用 simple_pattern_split 分词器。

它比 pattern 分词器更高效,因为它使用了不支持回溯的简化正则表达式。

但在本文开篇提到的场景中,char_group 分词器已经足够满足需求。

由于 URL 中可能包含编码字符或特殊符号,我们可以根据实际情况调整分词字符集。

5、小结

没有方案或者网上搜不到方案,AI 不能提供具体方案的时候,可以挨个试一下已有方案,逐步找到适合自己业务场景的最佳方案。

使用 char_group 分词器能够在不增加集群压力的情况下,实现对完整 URL 的精准分词。该方案简单高效,适合处理大量数据。

更多推荐

  1. Elasticsearch 使用误区之一------将 Elasticsearch 视为关系数据库!

  2. Elasticsearch 使用误区之二------频繁更新文档

  3. Elasticsearch 使用误区之三------分片设置不合理

  4. Elasticsearch 使用误区之四------不合理的使用 track_total_hits

  5. Elasticsearch 使用误区之五------单次请求获取大量数据

  6. 《一本书讲透 Elasticsearch》读者群的创新之路

  7. Elasticsearch 8.X 复杂分词搞不定,怎么办?

  8. Elasticsearch自定义分词,从一个问题说开去

更短时间更快习得更多干货!

和全球2000+ Elastic 爱好者一起精进!

elastic6.cn------ElasticStack进阶助手

抢先一步学习进阶干货!

相关推荐
SelectDB20 小时前
Apache Doris Python UDF:让 SQL 直接调用 Python 生态,支撑 Agent 时代复杂业务逻辑
大数据·数据库·python
ApacheSeaTunnel1 天前
当多表数据涌入,Apache SeaTunnel 如何巧妙化解主键冲突?
大数据·开源·数据集成·seatunnel·技术分享·数据同步
Elasticsearch1 天前
使用 Elastic Agent Builder 和 Sarvam AI 构建多语言语音 agent
elasticsearch
大大大大晴天4 天前
Hudi Metadata Table 与 Hive Sync (HMS)怎么选?
大数据
手可摘星辰7774 天前
一次线上FlinkCDC异常排查复盘
大数据·flink
大大大大晴天4 天前
Hudi技术内幕:Metadata Table原理与实践
大数据
武子康5 天前
调查研究-197 FAISS vs Elasticsearch 全面对比:从向量检索、全文搜索到 RAG 选型指南
人工智能·elasticsearch·agent
大大大大晴天5 天前
Hudi技术内幕:深入解析Index索引机制
大数据
阿里云大数据AI技术5 天前
Flink Forward Asia 2026 深圳启幕:Agentic Streaming for AI,开启实时智能新范式
大数据·flink
SelectDB6 天前
阶跃星辰基于 SelectDB 构建 PB 级 Agent 可观测平台
大数据·数据库·aigc