ES特殊字符查询

背景

项目使用ES做搜索引擎,大家都知道query_string这个API是支持lucene语法的,所以我们使用这个API支持用户个性化的搜索。项目上线后,用户搜索发现特殊字符无法搜索到而且也无法高亮。

原因与解决

因为我们的index没有指定分词器所以默认使用的是standard分词器。standard分词器会根据特殊字符或者空格将字符串进行切割,分成一个个词进行存储,那么来看一下standard分词器会把带有特殊字符的字符串解析成哪些词进行存储呢?

GET _analyze
{
  "analyzer": "standard",
  "text": ["A2654|10|09|022"]
}

非常明显, 在经过standard分词器分词时,"A2654|10|09|022",已经被分成了4个词,显然没有了特殊符号,这也就意味着如果我的index使用的是standard分词器数据入库时已经没有特殊符号了,所以后续使用特殊符号搜索一定是无法搜索到的。

//设置索引
PUT test003
{
  "mappings": {
    "doc": {
      "properties": {
        "text": {
          "analyzer": "standard",
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        }
      }
    }
  }
}

//插入数据
POST test003/doc
{
  "text":"A2654|10|09|022"
}

//查询
GET test003/_search
{
  "query": {
    "query_string": {
      "query": "\\|"
    }
  }
}

一切都符合预期,这也就是为什么我们线上搜索不到数据的原因。

那么如何才能做到特殊字符搜索呢?

了解了一些分词器发现了ngram分词器。

NGram 分词器

看一下描述

 什么意思呢?大概就是说会象是滑动窗口一样将字符进行指定长度的分割,对于那种没有空格很长的语言如德语很有效果。

这样看就很清楚了 ,NGram会根据我们指定窗口(分割长度)大小进行分词而不是特殊字符或者空格,这就意味着特殊字符也会被分成一个词。

那么既然是指定长的那么指定长度如何设置呢?还有其他的参数么?

现在我们来试一试

//设置index
PUT specialchar001
{
  "settings": {
    "analysis": {
      "analyzer": {
        "specialchar_analyzer": {
          "tokenizer": "specialchar_tokenizer"
        }
      },
      "tokenizer": {
        "specialchar_tokenizer": {
          "type": "ngram",
          "min_gram": 1,
          "max_gram": 2
        }
      }
    }
  },
  "mappings": {
    "_doc": {
      "properties": {
        "text": {
          "analyzer": "specialchar_analyzer",
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        }
      }
    }
  }
}

//插入数据
POST specialchar001/_doc
{
  "text": "A2654|10|09|022"
}

//特殊字符查询
GET specialchar001/_search
{
  "query": {
    "query_string": {
      "query": "\\|"
    }
  }
}

 

可以看到含有特殊字符的数据已经被查出来了。

那么我们看一下这个词被分成了什么样子

GET specialchar001/_analyze
{
  "analyzer": "specialchar_analyzer",
  "text": ["A2654|10|09|022"]
}
{
  "tokens" : [
    {
      "token" : "A",
      "start_offset" : 0,
      "end_offset" : 1,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "A2",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "word",
      "position" : 1
    },
    {
      "token" : "2",
      "start_offset" : 1,
      "end_offset" : 2,
      "type" : "word",
      "position" : 2
    },
    {
      "token" : "26",
      "start_offset" : 1,
      "end_offset" : 3,
      "type" : "word",
      "position" : 3
    },
    {
      "token" : "6",
      "start_offset" : 2,
      "end_offset" : 3,
      "type" : "word",
      "position" : 4
    },
    {
      "token" : "65",
      "start_offset" : 2,
      "end_offset" : 4,
      "type" : "word",
      "position" : 5
    },
    {
      "token" : "5",
      "start_offset" : 3,
      "end_offset" : 4,
      "type" : "word",
      "position" : 6
    },
    {
      "token" : "54",
      "start_offset" : 3,
      "end_offset" : 5,
      "type" : "word",
      "position" : 7
    },
    {
      "token" : "4",
      "start_offset" : 4,
      "end_offset" : 5,
      "type" : "word",
      "position" : 8
    },
    {
      "token" : "4|",
      "start_offset" : 4,
      "end_offset" : 6,
      "type" : "word",
      "position" : 9
    },
    {
      "token" : "|",
      "start_offset" : 5,
      "end_offset" : 6,
      "type" : "word",
      "position" : 10
    },
    {
      "token" : "|1",
      "start_offset" : 5,
      "end_offset" : 7,
      "type" : "word",
      "position" : 11
    },
    {
      "token" : "1",
      "start_offset" : 6,
      "end_offset" : 7,
      "type" : "word",
      "position" : 12
    },
    {
      "token" : "10",
      "start_offset" : 6,
      "end_offset" : 8,
      "type" : "word",
      "position" : 13
    },
    {
      "token" : "0",
      "start_offset" : 7,
      "end_offset" : 8,
      "type" : "word",
      "position" : 14
    },
    {
      "token" : "0|",
      "start_offset" : 7,
      "end_offset" : 9,
      "type" : "word",
      "position" : 15
    },
    {
      "token" : "|",
      "start_offset" : 8,
      "end_offset" : 9,
      "type" : "word",
      "position" : 16
    },
    {
      "token" : "|0",
      "start_offset" : 8,
      "end_offset" : 10,
      "type" : "word",
      "position" : 17
    },
    {
      "token" : "0",
      "start_offset" : 9,
      "end_offset" : 10,
      "type" : "word",
      "position" : 18
    },
    {
      "token" : "09",
      "start_offset" : 9,
      "end_offset" : 11,
      "type" : "word",
      "position" : 19
    },
    {
      "token" : "9",
      "start_offset" : 10,
      "end_offset" : 11,
      "type" : "word",
      "position" : 20
    },
    {
      "token" : "9|",
      "start_offset" : 10,
      "end_offset" : 12,
      "type" : "word",
      "position" : 21
    },
    {
      "token" : "|",
      "start_offset" : 11,
      "end_offset" : 12,
      "type" : "word",
      "position" : 22
    },
    {
      "token" : "|0",
      "start_offset" : 11,
      "end_offset" : 13,
      "type" : "word",
      "position" : 23
    },
    {
      "token" : "0",
      "start_offset" : 12,
      "end_offset" : 13,
      "type" : "word",
      "position" : 24
    },
    {
      "token" : "02",
      "start_offset" : 12,
      "end_offset" : 14,
      "type" : "word",
      "position" : 25
    },
    {
      "token" : "2",
      "start_offset" : 13,
      "end_offset" : 14,
      "type" : "word",
      "position" : 26
    },
    {
      "token" : "22",
      "start_offset" : 13,
      "end_offset" : 15,
      "type" : "word",
      "position" : 27
    },
    {
      "token" : "2",
      "start_offset" : 14,
      "end_offset" : 15,
      "type" : "word",
      "position" : 28
    }
  ]
}

结果符合预期,同时也说明了问题。当我使用standard分词器我得词只有4个,而用ngram后29个词!这说明:使用ngram势必要占用更多的空间!

使用相同的数据插入选择不同的分词器可以看到确实如此

 

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ElasticSearch查询构建器 该chrome扩展程序提供了易于使用的界面来配置不同的权重并动态增强选定字段的搜索结果,这将通过提供获得所需搜索结果所需的索引设置和文档映射来减少学习曲线,并为您可以通过在ES中运行相同的查询来减少开发时间,并在“结果”面板中显示结果。 可以在运行时更改设置以微调搜索结果,并将所有设置保存在“收藏夹”中,以备后用。 连接到ElasticSearch Server:提及正在运行ES的主机和端口(10.240.0.251:9200),然后按connect按钮。 构建查询:连接到服务器后,它将在可用的“索引和文档”下拉列表中列出所有索引及其对应的文档。 选择要为其生成查询的文档。现在,在“配置”选项卡下,您可以看到所选文档的所有字段的列表。 “配置”选项卡“动态得分”下的“选项”:它用于从多个匹配记录中提升特定记录,该匹配记录除了具有搜索关键字之外,还具有在booster字段中定义的值。 以相同顺序搜索:优先考虑以相同顺序找到的单词,而不是以相同顺序反对在同一行中找到的单词。 特殊字符:这将允许搜索字母数字,camelCase和用特殊字符(如(_,-等)分隔的单词。 生成查询:基于选定的选项,它将动态生成所需的索引设置,文档映射并构建查询。 “配置”选项卡权重下的选项:如果在多个字段中找到相同的单词,则用于为该字段赋予优先级。 给定字段得分更高的记录将被赋予更高的优先级,并排在首位。 过滤器:用于过滤掉从查询中收到的结果。如果选择了任何过滤器和值,则只会显示满足过滤条件的记录。 可以通过按+/-按钮在不同的数字字段上添加/删除类似(必须,范围)的过滤器。在结果中显示:这允许配置要在结果中看到的字段。您可以选择结果数要与默认情况下要查看的字段一起显示,将显示前五个字段。 您可以根据需要选择任何字段。 查询结果将显示在表格中。 在字段中搜索:这使用户可以选择要为给定查询搜索的文档字段。 显示结果:此按钮将带有要搜索的单词以及要显示的结果的最大大小,并建立一个动态查询,该查询针对选择的文档索引触发,它将获取结果并显示在结果面板下。 支持语言:English

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值