记录一个ES分词器不生效的解决过程

news2025/2/22 2:08:58

问题背景

商城项目,其中商品查询检索使用的是ES, 但存在某些商品查询不到的问题
例如:某商品名包含AA_BBB这样的关键词,但是搜索"AA"不能查询到该商品,但是将商品名修改为AA BBB后就能查询到了.
怀疑是分词的问题,但看代码,在创建ES索引时在对应字段上也定义了分词器,但是不知道什么原因不好用,于是开始了问题调查

解决过程

解决过程比较坎坷,调查问题时由于我不怎么会ES,所以只能边搜索边调查,好在最后解决了问题.由于时间过去很久了,没留存截图和代码,只能简要复述一下
查询字段: name
查询条件: AA
商品名为 AA_BBB时无法查询出,改为AA BBB可以查询到

  1. 还原DSL,尝试简化条件后检索
    由于是业务相关的检索,调用接口查询ES时必然会除了关键词还有一些其他的查询条件,比如排序啊,分页啊,价格区间等等,所以结合日志还原DSL,省略掉其他的查询条件后一样无法查询到; 但直接使用ik分词对商品名进行分词后可以分词出所使用的查询关键词
  2. 仔细查阅了一下构建DSL进行搜索的代码, 未查看到疑点, 语句构建时没有异常
  3. 于是又查阅了一下ES索引创建的语句,发现在需要分词字段上都定义了分词器
    在这里插入图片描述
  4. 于是尝试分析搜索的向量命中情况,发现确实未命中对应doc,说明分词或查询确实有问题
  5. 此时已经焦头烂额了…后来,考虑到从头复现一次,于是在本地安装了一个ES,版本与测试环境相同,使用代码里的语句创建索引,并写入了两个商品,名称分别为AA BBB和AA_BBB
  6. 尝试搜索后AA后发现依然无法查询到AA_BBB的文档,很诡异. 于是尝试查看了一下所创建的索引mapping,发现name字段上并没有analyzer!查看测试环境的实际业务索引,确实也没有analyzer! 至此已经发现了问题所在——ES索引创建定义analyzer异常
  7. 既然定位到问题了,就可以找到解决问题的方法了,于是查阅了一下资料,发现系统所使用的ES7版本,在创建索引时,除了在mapping中定义字段及analyzer时,还需要在定义setting时需要增加analysis配置,否则定义的分词器会不生效,即在创建mapping时需要有 如下配置
"analysis":
    {
        "analyzer":
        {
            "ik":
            {
                "tokenizer": "ik_max_word"
            }
        }
    }
  1. 至此,重新创建索引后检查mapping,发现字段上已经定义了ik分词器了,重新写入两个doc之后发现搜索AA可以搜索到AA_BBB和AA BBB了, 问题解决!撒花!★,°:.☆( ̄▽ ̄)/$:.°★

最终解决

总结就是项目中的索引创建代码版本可能比较旧,在ES7上有些不再适用(其实发现问题后发现有的字段类型是string,但是其实ES7已经不再支持string类型,而是使用keywords和text了,所以进一步说明是ES相关代码的版本有问题)
最终解决问题的索引创建代码如下:

// 创建索引
public boolean createIndex(String indexName) {
        if (isIndexExist(indexName)) {
            log.info("Index is exits!");
            return true;
        }

        CreateIndexResponse createIndexResponse = null;
        try {
            //创建映射
            XContentBuilder mapping = null;
            mapping = getMappingBuilder();
            // 初始化settings
            XContentBuilder settings = getIndexSettings();
//            CreateIndexRequest request = new CreateIndexRequest(indexName).source(mapping);
            CreateIndexRequest request = new CreateIndexRequest(indexName)
                    .settings(settings)
                    .mapping(mapping);
            //设置创建索引超时2分钟
            request.setTimeout(TimeValue.timeValueMinutes(2));
            createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("createIndex error ! e:{}", e);
        }
        return createIndexResponse.isAcknowledged();
    }

// 定义mapping
private XContentBuilder getMappingBuilder(){
        XContentBuilder mapping = null;
        try {
            // 修改type类型,string->text/keyword,decimal-?double --update on 2024/8/1 by MaYue
            mapping = XContentFactory.jsonBuilder()
                    .startObject()
                    .startObject("properties")
                    //.startObject("m_id").field("type","keyword").endObject()  //m_id:字段名,type:文本类型,analyzer 分词器类型
                    //该字段添加的内容,查询时将会使用ik_max_word 分词 //ik_smart  ik_max_word  standard
                    .startObject("id")
                    .field("type", "keyword")
                    .endObject()
                    // ES7已无string类型, 把需要分词的字段改成text
                    .startObject("name")
                    .field("type", "text")
                    .field("analyzer", "ik_max_word")
                    .endObject()
                    .endObject()
                    // .......其他字段省略
                    // settings单独设置,这段放到getIndexSettings方法里了
//                    .startObject("settings")
//                    //分片数
//                    .field("number_of_shards", 3)
//                    //副本数
//                    .field("number_of_replicas", 1)
//                    .endObject()
                    .endObject();
        } catch (IOException e) {
            log.error("createGoodsIndex error ! e:{}", e);
        }
        return mapping;
    }

// 定义settings
private XContentBuilder getIndexSettings() {
        XContentBuilder settings = null;
        try {
            settings = XContentFactory.jsonBuilder()
                    .startObject()
                    // 分片/副本设置
                    //分片数
                    .field("number_of_shards", 3)
                    //副本数
                    .field("number_of_replicas", 1)
                    // 增加分词器设置,否则创建mapping时指定analyzer不生效
                    // "analysis" : {
                    //          "analyzer" : {
                    //            "ik" : {
                    //              "tokenizer" : "ik_max_word"
                    //            }
                    //          }
                    //        }
                    .startObject("analysis")
                    .startObject("analyzer")
                    .startObject("ik")
                    .field("tokenizer","ik_max_word")
                    .endObject()
                    .endObject()
                    .endObject()
                    .endObject();
        } catch (IOException e) {
            log.error("createGoodsIndex error ! e:{}", e);
        }
        return settings;
    }

一些吐槽

最近入职了一家新公司,是做电商类项目的,其中商品查询检索那部分用的是ES. 刚来的时候不熟悉项目,也暂时没有新的需求给我,就主要熟悉一下项目,顺便给了我一个排查一些商品无法正常搜索出来的问题.比如此博文所记录的这个问题
但是在此之前其实我完全没用过ES, 招聘JD上写了ES但是我并不会面试的时候也没问过相关问题,而我还通过了面试…所以接到这个任务后基本上是现学的,粗略看了一下ES相关名词的定义,然后面向搜索引擎调查问题,查一点,学一点,最后居然解决了问题…总有种"当你在简历上吹了牛,但是获得了这份工作"的不真实感…
后续考虑系统地学习一下ES,并尝试优化一下现有的搜索逻辑,现在的搜索只是一个很基础的商品名称搜索,其实还有很多优化点,例如权重、字典、分词器等,开个坑吧!等我学会了来填!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2302202.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高性能内存对象缓存Memcached详细实验操作

目录 前提准备: cache1,2: 客户端cache-api(一定得是LAMP环境) memcache实现主主复制以及高可用(基于以上完成) cache1,2: memcachekeepalived(基于以上完成) cache1,2: 前提准备: 1. 准备三台cent…

css之display:grid布局改块级元素布局

1.问题: div是块级元素,一个div元素占一行,但是,今天测试样式时,总是会有两个div并占一行,很困惑,结果发现是app这个样式 在main.css里 #app样式布局在main.ts里被应用 2.原因以及样式分析 im…

推荐一个github star45k+进阶的java项目及知识的网站

mall是github上star 45k的一个java项目 mall项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBootMyBatis实现,采用Docker容器化部署。 前台商城系统包含首页门户、商品推荐、商品搜索、商品展示、购物车、订单流程、会员中心…

第2章 深入理解Thread构造函数

Thread的构造函数。 2.1 线程的命名 在构造一个Thread时可以为其命名。 2.1.1 线程的默认命名 下面构造函数中,并没有为线程命名。 Thread() Thread(Runnable target) Thread(ThreadGroup group, Runnable target)打开源码会看到 public Thread(Runnable targe…

node 使用 Redis 缓存

缓存是什么? 高并发下,一个项目最先出问题的,并不是程序本身,而是数据库最先承受不住。 在数据库上我们可以做很多优化,例如优化 SQL 语句,优化索引,如果数据量大了,还可以分库、分表…

PMBOK第7版整体架构全面详解

1. 引言 7月1日对于项目管理从业者和研究者而言,是个非凡意义的一个时间,这一天,翘首以待的《 项 目管理知识体系指南 》(PMBOK)第七版终于发布了。 总体而言,PMBOK第七版集百家之所长,成一…

【Scrapy】Scrapy教程6——提取数据

前一小节我们拿到了页面的数据,那页面中那么多内容,我们想要其中的部分内容,该如何获取呢?这就需要对我们下载到的数据进行解析,提取出来想要的数据,这节就讲讲如何提取数据。 引入 我们编辑保存下来的shouye.html文件看下,发现这是什么鬼,全是如下图的代码。 没错…

golang panic信息捕获

背景 我们的日志接入阿里云sls平台,但是,日志是以json的格式存储在阿里云sls平台上,程序中产生的error,info等日志都可以实现以json的格式打印。但是,golang程序中产生的panic信息本身不是以json的格式输出,这就导致p…

一周学会Flask3 Python Web开发-http响应状态码

锋哥原创的Flask3 Python Web开发 Flask3视频教程: 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 在Flask程序中,客户端发出的请求触发相应的视图函数,获取返回值会作为响应的主体,最后生成…

goland无法debug项目

1、其实个原因是因为正在使用的Delve调试器版本太旧,无法兼容当前的Go语言版本1.2。Delve是Go语言的一个调试工具,用于提供源码级别的调试功能。Go语言每隔一段时间会发布新版本,而相应的调试器Delve也可能会更新以提供新的特性或修复已知问题…

Python VsCode DeepSeek接入

Python VsCode DeepSeek接入 创建API key 首先进入DeepSeek官网,https://www.deepseek.com/ 点击左侧“API Keys”,创建API key,输出名称为“AI” 点击“创建",将API key保存,复制在其它地方。 在VsCode中下载…

Ubuntu22.04.6如何固定ip地址

Ubuntu22.04.6如何固定ip地址 主要参见这篇博客 ubuntu 桌面版如何设置固定IP地址_ubuntu桌面版如何修改ip-CSDN博客 1.先查看一下当前的IP是多少

腿足机器人之十- SLAM地图如何用于运动控制

腿足机器人之十- SLAM地图如何用于运动控制 腿足机器人SLAM地图的表示与处理全局路径规划:地形感知的路径搜索基于A*的三维路径规划基于RRT*的可行步态序列生成 局部运动规划:实时步态调整与避障动态窗口法的腿足适配模型预测控制(MPC&#x…

毕业项目推荐:基于yolov8/yolov5/yolo11的果蔬检测识别系统(python+卷积神经网络)

文章目录 概要一、整体资源介绍技术要点功能展示:功能1 支持单张图片识别功能2 支持遍历文件夹识别功能3 支持识别视频文件功能4 支持摄像头识别功能5 支持结果文件导出(xls格式)功能6 支持切换检测到的目标查看 二、数据集三、算法介绍1. YO…

pyside6学习专栏(二):程序图像资源的加载方式

pyside6中的QLabel控件可以加载图像和gif动画,可以直接从外部文件加载,也可以从QRC类型的文件(实际是一脚本文件)经编绎生成对应的资源.PY模块文件(就是将qrc文本中指定的资源文件的16制内容写入.py文件)来使用,本文对两种方式作了一简单的示…

如何在 VS Code 中快速使用 Copilot 来辅助开发

在日常开发中,编写代码往往是最耗时的环节之一。而 GitHub Copilot,作为一款 AI 编码助手,可以帮助开发者 自动补全代码、生成代码片段,甚至直接编写完整的函数,大幅提升编码效率。那么,如何在 VS Code 中快…

DeepSeek-R1论文阅读及本地调用

前言 DeepSeek已经火了一段时间了,对于这项“国运级”的技术成果,即便研究的不是这个方向,也不免好奇前来看看。本文将先解析一下DeepSeek-R1这篇论文,再对DeepSeek的本地部署使用进行研究配置。 论文标题:DeepSeek-…

自然语言处理:第九十二章 chatBI 经验(转载)

本人项目地址大全:Victor94-king/NLP__ManVictor: CSDN of ManVictor 原文连接: 一文分享 ChatBI 实践经验 写在前面: 笔者更新不易,希望走过路过点个关注和赞,笔芯!!! 写在前面: 笔者更新不易,希望走过路过点个关注和赞&#x…

体验用ai做了个python小游戏

体验用ai做了个python小游戏 写在前面使用的工具2.增加功能1.要求增加视频作为背景。2.我让增加了一个欢迎页面。3.我发现中文显示有问题。4.我提出了背景修改意见,欢迎页面和结束页面背景是视频,游戏页面背景是静态图片。5.提出增加更多游戏元素。 总结…

懒人精灵本地离线卡密验证系统教程(不联网、安全稳定、省钱、永久免费、无任何限制)

1.合集懒人精灵本地离线卡密验证系统教程(不联网、安全稳定、省钱、永久免费、无任何限制):https://www.bilibili.com/video/BV1M6rdYEEog/ 备注: 1.本地离线卡密采用最安全的非对称加解密技术,设备id采用最安全多重混合加密不可逆技术生成&…