本文目录
- 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 或 keyword,es 自动创建的索引 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 建立的字段类型,可能不是我们期望的。
完结!