本文目录

一、基本环境

二、问题现象

三、案例介绍

四、问题原因

五、解决方案

第一步:删除索引

第二步:重建索引

第三步:触发程序灌数据

六、总结


一、基本环境

  • elasticsearch 版本:7.11.1
  • 客户端环境:kibana v7.11.1、Java8 应用程序模块。

其中 kibana 主要用于数据查询诊断和查阅日志,Java8 为主要的客户端,数据插入和查询都是由Java 实现的。

二、问题现象

共有三个部署环境,一个是开发环境、一个是测试环境、一个是正式环境。

前提:APP的首页搜索功能(搜索设备列表和搜索智能列表)在开发环境和正式环境一切正常。

测试人员在测试APP的首页搜索功能(搜索设备列表和搜索智能列表),发现搜索智能列表功能正常,而搜索设备时,无数据。

使用 kibana 里的开发工具查询时单个汉字可以搜索出设备列表,而使用词语去搜索设备时一直搜索不到任何数据。

查询数据命令:命令 索引/_search

下图中的命令是查询该索引下的所有数据

示例(根据某一字段查询)如下:

GET device-name-index/_search
{
  "query": {
    "bool": {
      "must": [
        {"term": {
          "deviceName": {
            "value": "开关"
          }
        }}
      ]
    }
  }
}

搜索“开”字可以把设备名称中带有“开”字的设备搜索出来,但是搜索“开关”词语时,设备名称中带有“开关”词语的设备结果为空(ES中实际上有数据)。

三、案例介绍

使用 elasticsearch 存储设备列表的主要信息,document 内的 field,基本上是 integer keywordes 自动创建的索引 device-name-index 如下:

查询 mapping 信息,命令如下:

GET device-name-index/_mapping

结果返回如下:

{
  "device-name-index" : {
    "mappings" : {
      "properties" : {
        "deviceId" : {
          "type" : "integer"
        },
        "deviceModel" : {
          "type" : "text"
        },
        "deviceName" : {
          "type" : "text"
        },
        "deviceType" : {
          "type" : "text"
        },
        "floorName" : {
          "type" : "text"
        },
        "id" : {
          "type" : "integer"
        },
        "roomName" : {
          "type" : "text"
        },
        "sn" : {
          "type" : "text"
        }
      }
    }
  }
}

而部署在开发环境里的 es 索引里的字段类型如下:

{
  "device-name-index" : {
    "mappings" : {
      "properties" : {
        "deviceId" : {
          "type" : "integer"
        },
        "deviceModel" : {
          "type" : "keyword"
        },
        "deviceName" : {
          "type" : "text",
          "fields" : {
            "ikmaxword" : {
              "type" : "text",
              "analyzer" : "ik_max_word"
            },
            "pinyin" : {
              "type" : "text",
              "analyzer" : "pinyin"
            }
          },
          "analyzer" : "standard"
        },
        "deviceType" : {
          "type" : "keyword"
        },
        "floorName" : {
          "type" : "keyword"
        },
        "roomName" : {
          "type" : "keyword"
        },
        "sn" : {
          "type" : "keyword"
        }
      }
    }
  }
}

以上字段,只需要关注 deviceName 即可。因为搜索是根据此字段检索数据的。

可以很清楚的看到 deviceName 字段使用了 ik分词器(ik_max_word)。

四、问题原因

按照 mapping 返回结果来看,部署在测试环境的字段 deviceName 没有添加 ik 分词器,而 es 采取的策略是,如果没有添加自定义的分词器,那么便会使用 es 默认的标准分词器分词,这就是导致单个字搜索时可以检索出数据,而使用词语检索数据时无数据的原因。

五、解决方案

第一步:删除索引

命令如下:

DELETE device-name-index

第二步:重建索引

命令如下:

PUT device-name-index
{
	"mappings": {
		"properties": {
			"deviceId": {
				"type": "integer"
			},
			"deviceModel": {
				"type": "keyword"
			},
			"deviceName": {
				"type": "text",
				"fields": {
					"ikmaxword": {
						"type": "text",
						"analyzer": "ik_max_word"
					},
					"pinyin": {
						"type": "text",
						"analyzer": "pinyin"
					}
				},
				"analyzer": "standard"
			},
			"deviceType": {
				"type": "keyword"
			},
			"floorName": {
				"type": "keyword"
			},
			"roomName": {
				"type": "keyword"
			},
			"sn": {
				"type": "keyword"
			}
		}
	}
}

第三步:触发程序灌数据

在我的项目中只需要修改设备名称即可触发数据内容变更(全量删除并全量更新),再次在APP首页搜索设备名称,单个字和词语都可以检索出数据,问题搞定。

使用ik分词器后,查看分词结果情况,命令格式:

GET 索引/_doc/索引下某字段_id/_termvectors?fields=字段名称.ikmaxword

使用es默认的分词器查看分词结果情况,命令:

GET 索引/_doc/索引下某字段_id/_termvectors?fields=字段名称

示例如下:

GET device-name-index/_doc/cO-TNIMBWdpBXCOgNBnM/_termvectors?fields=deviceName.ikmaxword

六、总结

问题虽小,但一定要追溯源头,比如此次测试环境的不规范操作。后期如果有删除索引的操作,应该先手动建立索引后,再灌数据,而不是直接让其自动 mapping 建立索引,自动 mapping 建立的字段类型,可能不是我们期望的。

完结!

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐