• Elasticsearch 8.X 路径检索的企业级玩法


    1、企业级实战问题

    问题描述如下:

    "path""hdfs://xx.xx.xx:8200/home/lht/aaa.doc"

    想检索到aaa文件。并且以doc为筛选条件。可行吗?

    就是我有文件数组。匹配到文件数组里的文件类型就检索出来?

    ——问题来源:GPVIP 微信群

    2、问题定义

    给定一个路径 path,期待实现:输入扩展名,可以实现检索?

    扩展要求:有没有专门针对 path 路径的检索或者相关实现?

    问题描述清楚了,接下来我们先做分析和方案的探讨。

    3、解决方案的探讨

    思考几个问题:

    • 问题1:传统的分词器能否搞得定?

    • 问题2:分词搞不定的话,预处理能协助搞定吗?

    • 问题3:落脚到题目的需求,最终探讨如何解决问题?!

    3.1 传统的分词器能否搞定?

    Elasticsearch 内置的分词器包含但不限于:

    • standard(默认分词器);

    • simple 分词器;

    • whitespace 分词器;

    • keyword 分词器

      等等.....

    我们拿标准分词器 standard 举例:

    1. DELETE test-index-20220917
    2. PUT test-index-20220917
    3. {
    4.   "mappings": {
    5.     "properties": {
    6.       "path": {
    7.         "type""text",
    8.         "analyzer""standard",
    9.         "fields": {
    10.           "keyword": {
    11.             "type""keyword"
    12.           }
    13.         }
    14.       }
    15.     }
    16.   }
    17. }
    18. POST test-index-20220917/_bulk
    19. {"index":{"_id":1}}
    20. {"path":"hdfs://xx.xx.xx:8200/home/lht/aaa.doc"}

    通过 analyze API 看看分词结果。

    1. POST _analyze
    2. {
    3.   "text": [
    4.     "hdfs://xx.xx.xx:8200/home/lht/aaa.doc"
    5.   ],
    6.   "analyzer""standard"
    7. }

    分词结果为:

    4ee19913d7be78a3d52629379b8f2eca.png

    如下的检索,standard 分词器检索不到!!

    1. POST test-index-20220917/_search
    2. {
    3.   "query": {
    4.     "match": {
    5.       "path""doc"
    6.     }
    7.   }
    8. }

    2.2 能否以扩展名进行检索?

    如上的仅 standard 标准分词搞不定扩展名的检索。主要原因分词无法分出扩展名。

    没有扩展名怎么办?需要借助数据预处理的方式来解决。

    当我们在写入ES 之前,我们需要把 扩展名提炼出来!

    模拟一把!

    1. POST _ingest/pipeline/_simulate
    2. {
    3.   "pipeline": {
    4.     "processors": [
    5.       {
    6.         "script": {
    7.           "description""Extract 'tags' from 'env' field",
    8.           "lang""painless",
    9.           "source""""
    10.             String[] envSplit = ctx['path'].splitOnToken(params['delimiter']);
    11.             int envArrayLen = envSplit.length;
    12.             ctx['extension'] = envSplit[envArrayLen -1];
    13.           """,
    14.           "params": {
    15.             "delimiter""."
    16.           }
    17.         }
    18.       }
    19.     ]
    20.   },
    21.   "docs": [
    22.     {
    23.       "_source": {
    24.         "path""hdfs://xx.xx.xx:8200/home/lht/aaa.pdf"
    25.       }
    26.     }
    27.   ]
    28. }

    结果包含扩展名,符合预期。

    模拟可以搞定,剩下的定义索引+指定缺省管道,必然也可以搞定。

    932fccbb024394399fed9af6ca084407.png

    篇幅原因,不再赘述。

    至此,扩展名问题通过 script 预处理管道可以搞定了!

    还有问题2亟待解决,那就是我们能否覆盖类似路径更全的场景?全部路径都能检索到!

    2.3 路径分词的解决方案实现

    提到分词器,大家脑海里立马要映射出分词器的“三段论”组成结构。

    第一:0或者多个 character filter 过滤器;

    第二:唯一的tokenizer;

    第三:0或多个 token filter 过滤器。

    0af84a735ddc278bc729aaa4c1791852.png

    通过官方文档,我们能找到有:Path hierarchy tokenizer。其实它就是我们一直想找的路径分词器。

    如何来使用?好不好用呢?

    拿个例子一看便知:

    1. POST _analyze
    2. {
    3. "tokenizer""path_hierarchy",
    4. "text""hdfs://xx.xx.xx:8200/home/lht/ccc.doc"
    5. }

    如下截图所示:至少初步达到预期,看着非常专业了!

    ad48967a7b6f97aa352548b680bb381d.png

    但,ccc.doc 没有给出分词结果,能否有参数可以搞定呢?

    可以的。reverse 默认 false,改成 true 就可以实现。

    实战如下:

    1. PUT my-index-000001
    2. {
    3.   "settings": {
    4.     "analysis": {
    5.       "analyzer": {
    6.         "my_analyzer": {
    7.           "tokenizer""my_tokenizer"
    8.         }
    9.       },
    10.       "tokenizer": {
    11.         "my_tokenizer": {
    12.           "type""path_hierarchy",
    13.           "delimiter""/",
    14.           "reverse"true
    15.         }
    16.       }
    17.     }
    18.   }
    19. }
    20. POST my-index-000001/_analyze
    21. {
    22.   "analyzer""my_analyzer",
    23.   "text""hdfs://xx.xx.xx:8200/home/lht/ccc.doc"
    24. }
    bc5e3af99d84dea3f9f62bbda18bf2d9.png

    有了这些,我们整合一下,其实能实现复杂的路径检索实现。

    整合如下:

    1. PUT _ingest/pipeline/extension_pipeline
    2. {
    3.   "processors": [
    4.     {
    5.       "script": {
    6.         "description""get file extension of path",
    7.         "lang""painless",
    8.         "source""""
    9.             String[] envSplit = ctx['path'].splitOnToken(params['delimiter']);
    10.             int envArrayLen = envSplit.length;
    11.             ctx['extension'] = envSplit[envArrayLen -1];
    12.           """,
    13.         "params": {
    14.           "delimiter""."
    15.         }
    16.       }
    17.     }
    18.   ]
    19. }
    20. PUT test-index-20220917-02
    21. {
    22.   "settings": {
    23.     "index": {
    24.       "default_pipeline""extension_pipeline"
    25.     },
    26.     "analysis": {
    27.       "analyzer": {
    28.         "custom_path_tree": {
    29.           "tokenizer""custom_hierarchy"
    30.         },
    31.         "custom_path_tree_reversed": {
    32.           "tokenizer""custom_hierarchy_reversed"
    33.         }
    34.       },
    35.       "tokenizer": {
    36.         "custom_hierarchy": {
    37.           "type""path_hierarchy",
    38.           "delimiter""/"
    39.         },
    40.         "custom_hierarchy_reversed": {
    41.           "type""path_hierarchy",
    42.           "delimiter""/",
    43.           "reverse""true"
    44.         }
    45.       }
    46.     }
    47.   },
    48.   "mappings": {
    49.     "properties": {
    50.       "path": {
    51.         "type""text",
    52.         "fields": {
    53.           "tree": {
    54.             "type""text",
    55.             "analyzer""custom_path_tree"
    56.           },
    57.           "tree_reversed": {
    58.             "type""text",
    59.             "analyzer""custom_path_tree_reversed"
    60.           }
    61.         }
    62.       }
    63.     }
    64.   }
    65. }
    66. POST test-index-20220917-02/_bulk
    67. {"index":{"_id":1}}
    68. {"path":"hdfs://xx.xx.xx:8200/home/lht/aaa.doc"}
    69. {"index":{"_id":2}}
    70. {"path":"hdfs://xx.xx.xx:8200/home/lht/bbb.pptx"}
    71. {"index":{"_id":3}}
    72. {"path":"hdfs://xx.xx.xx:8200/home/lht/ccc.doc"}

    简单解释一下:

    • 第一:定义了预处理器,通过脚本获取了路径的扩展名。

    • 第二:定义了正向和反向的两个分词器,实现了路径的全覆盖分词。

    • 第三:导入了数据。

    用了一个分词器的两种不同的实现方式,实现了正向路径和反向路径的双重检索,同时加了类型的精准匹配!

    1. POST test-index-20220917-02/_search
    2. {
    3.   "query": {
    4.     "bool": {
    5.       "must": [
    6.         {
    7.           "term": {
    8.             "extension.keyword": {
    9.               "value""doc"
    10.             }
    11.           }
    12.         },
    13.         {
    14.           "match": {
    15.             "path.tree_reversed""home/lht/aaa.doc"
    16.           }
    17.         },
    18.         {
    19.           "match": {
    20.             "path.tree""hdfs://xx.xx.xx:8200/home/lht"
    21.           }
    22.         }
    23.       ]
    24.     }
    25.   }
    26. }

    如下的结果达到预期。

    ff21c1425ea76b1dc4a61af15a62a978.png

    3、小结

    43dbd922957b8a6244275b0fbe0390ae.png

    通过 script 预处理获取到的路径中文件的扩展名,以便后续继续扩展名进行检索。

    没有使用 standard 标准分词器,而是使用路径相关的 path 路径的正向和反向的分词器来解决路径检索问题,path 路径相关的检索都推荐使用!

    你有没有遇到类似问题,如何解决的呢?欢迎留言交流。

    4、视频讲解如下

    推荐阅读

    1. 如何从0到1打磨一门 Elasticsearch 线上直播课?

    2. 重磅 | 死磕 Elasticsearch 方法论认知清单(2021年国庆更新版)

    3. 如何系统的学习 Elasticsearch ? 

    4. Elasticsearch 自定义分词同义词环节的这个细节不大好理解......

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

    e9743560c8725d02603e02d91dbba273.jpeg

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

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

    35cdf4ef570b11c1dc83bf3099d4b088.gif

    比同事抢先一步学习进阶干货!

  • 相关阅读:
    测试用例设计指南
    cjson报错
    负载姜黄素的葡聚糖修饰的钆掺杂的空心介孔二氧化硅纳米材料(科研级)
    Node.js中Buffer API详解
    安全防护功能强,多御安全浏览器更安全
    双指针算法
    效率工具之Arthas
    功能测试【测试用例模板、Bug模板、手机App测试】
    常用MII接口详解
    java: 读取snakeyaml-1.26.jar各种jar包时出错; error in opening zip file
  • 原文地址:https://blog.csdn.net/wojiushiwo987/article/details/126945075