elasticsearch通配符和正则表达式查询

通配符(wildcard)和正则表达式查询(regexp),相关的还有prefix前缀查询(前缀查询我们这里用不到,不做过多说明),他们都是底层基于词的查询,注意事基于词的,其工作方式就是扫描倒排索引中的词列表才能找到所有匹配的词,然后依次获得每个词的文档ID,这三种查询都需要考虑性能问题,为了节省资源,要避免使用左通配这样的模式匹配(如: foo 或 .foo 这样的正则式)。
prefix 、 wildcard 和 regexp 查询是基于词操作的,如果用它们来查询 analyzed 字段,它们会检查字段里面的每个词,而不是将字段作为整体来处理。
比方说包含 “Quick brown fox” (快速的棕色狐狸)的 title 字段会生成词: quick、brown和fox:
{ "regexp": { "title": "br.*" }}//会匹配到
{ "regexp": { "title": "Qu.*" }} //不会匹配到,因为索引里是quick而不是Quick
{ "regexp": { "title": "quick br*" }} //不会匹配到,因为quick和brown在词表(倒排索引)中是分开的

基于以上分析,因为我们项目的字段处理都是分词的,所以需要查询字段对应的keyword字段,这一点很重要,之前没有这么做,是导致正则查询不准确的原因之一。

  • 通配符查询

    通配符查询后台会直接查询分词字段
    常用的通配符有:?匹配任意字符,*匹配0或多个字符,.匹配单个字符等等,这些规则与正则里边的使用大多是类似的。比如查询李又亭,可以直接这样通配“李又.”

  • 正则表达式查询

    正则表达式查询后台会查询keyword字段
    这里我们使用的查询语法应该是Lucene regular expression engine支持的语法,正则表达式语法在这里只支持一些常用的,所以这里也仅介绍Lucense支持的语法。es查询语法中只有regexp和query_string查询支持正则,我们所使用的就是query_string查询,query_string支持很多语法,以/开始和结束时es会认为是正则表达式查询,正常我们在写正则表达式的时候,需要以^标识开始,以$标识结束,称之为Anchor,Lucene总是会帮我们做这一步,所以不需要标识开始和结束。
    首先某些特定字符被做为了保留字,使用的时候必须要转义,转义的意思是如果你真正要查的内容是这些字符的时候需要在字符前边加"",比如“*”、"+" 、"\",这些字符包括:
    . ? + * | { } [ ] ( ) " \ # @ & < > ~
    还有就是,以""包起来的内容需要全部匹配( interpreted literally),举个栗子:有字符串“李又亭”,正则表达式"/"李2亭"/"是匹配不上的

    1. ''."代表任意字符,比如有字符串"abcde"
      ab... # match
      a.c.e # match
    2. "+"代表加号之前的最小单元匹配一次或多次,比如有字符串“aaabbb”
      a+b+ # match
      aa+bb+ # match
      a+.+ # match
      aa+bbb+ # match
    3. ""代表星号之前的最小单元匹配零次次或多次,比如有字符串“aaabbb”
      a
      b* # match
      abc* # match
      .bbb. # match
      aaabbb # match
    4. "?"代表星号之前的最小单元匹配零次次或一次,比如有字符串“aaabbb”
      aaa?bbb? # match
      aaaa?bbbb? # match
      .....?.? # match
      aa?bb? # no match
    5. "{}"可以被用来声明之前的最小单元出现一个最小次数和最大次数,比如:
      {5} # repeat exactly 5 times
      {2,5} # repeat at least twice and at most 5 times
      {2,} # repeat at least twice
      比如有一个字符串"aaabbb"
      a{3}b{3} # match
      a{2,4}b{2,4} # match
      a{2,}b{2,} # match
      .{3}.{3} # match
      a{4}b{4} # no match
      a{4,6}b{4,6} # no match
      a{4,}b{4,} # no match
    6. "()"被用来分组构成一个最小单元或者说是子模式,比如有一个字符串"ababab":
      (ab)+ # match
      ab(ab)+ # match
      (..)+ # match
      (...)+ # no match
      (ab)* # match
      abab(ab)? # match
      ab(ab)? # no match
      (ab){3} # match
      (ab){1,2} # no match
    7. "|"可以作为一个或的操作符,符号左右侧的内容有一个匹配上就认为是匹配成功,这里注意这个匹配是最长匹配,而不是最短匹配(这一点可以看下边例子好好体会一下),比如有''aabb"
      aabb|bbaa # match
      aacc|bb # no match
      aa(cc|bb) # match
      a+|b+ # no match
      a+b+|b+a+ # match
      a+(b|c)+ # match
    8. "[]"作为一个选择符,意思是中括号内的任意字符出现都认为是匹配成功,加上代表相反的意思,也就是说后的任意字符不出现都认为是匹配成功。
      [abc] # 'a' or 'b' or 'c'
      [a-c] # 'a' or 'b' or 'c'
      [-abc] # '-' or 'a' or 'b' or 'c'
      [abc-] # '-' or 'a' or 'b' or 'c'
      [^abc] # any character except 'a' or 'b' or 'c'
      [^a-c] # any character except 'a' or 'b' or 'c'
      [^-abc] # any character except '-' or 'a' or 'b' or 'c'
      [^abc-] # any character except '-' or 'a' or 'b' or 'c'
      上边出现的破折号(-)意思是一个连续区间,比如[a-z]表示小写字母a到小写字母z的共26个字符中的任意字符,[0-9]表示0到9的共10个字符中的任意字符,如果想表示字符本身就需要转义,比如[^abc-] 表示匹配除了a、b、c、-之外的任意字符。关于破折号,比如有字符串:"abcd":
      ab[cd]+ # match
      [a-d]+ # match
      [^a-d]+ # no match
      可选操作符(在正则表达式中也支持一些特殊的操作符,可以使用flags字段控制是否开启,下边都是可选操作符)
    9. “~”,Complement(波浪线),比如有正则表达式"ab~cd"的意思是1>必须要以a开头;2>a后边必须跟着b;3>b后边跟着任意长度的字符比如aa,b,d等等但不能是单个字符c;4>必须以d结尾,再比如有字符串"abcdef":
      ab~df # match
      ab~cf # match
      ab~cdef # no match
      a~(cb)def # match
      a~(bc)def # no match

    10."<>",Interval,支持一个数值的范围,比如有"foo80":
    foo<1-100> # match
    foo<01-100> # match
    foo<001-100> # no match

    11."&",Intersection,可以实现多个匹配的连接,比如有字符串"aaabbb":
    aaa.+&.+bbb # match
    aaa&bbb # no match
    12."@",Any,可以匹配任意的字符串
    @&~(foo.+) # anything except string beginning with "foo"

    附录:

    上边介绍了一些Lucene支持的常用正则语法,相信你已经知道该怎么写自己的正则表达式了,如果还不是很清楚具体怎么写,这里再举个详细的栗子。

    比如现在es里有这样两个文档:

      {
         "1_t": "1",
         "dataType": null,
         "dataSource": 2,
         "2_t": "蒋仁杰",
         "3_t": "China",
         "4_t": "CT1439201",
         "5_t": "蒋仁杰-China"
     }
     {
         "1_t": "8",
         "dataType": null,
         "dataSource": 2,
         "2_t": "李又亭",
         "3_t": "China",
         "4_t": "WB2661715",
         "5_t": "8-��亭",
         "6_t": " 000000008--李又亭 --China --WB2661715 --8-?????????"
     }
    
    1. 根据姓名查询姓蒋的,正则应该是这样:/蒋.+/ 或者/蒋.{1,}/
    2. 根据姓名查询姓蒋的,然后名字是两个字的文档,正则应该是这样:/蒋.{2}/
    3. 查询姓名是蒋仁杰或者李又亭的,正则应该这样写:/(蒋仁杰)|(李又亭)/
    4. 查询姓名是李又亭或者张又亭或者王又亭的,正则应该这样写:/[李张王]又亭/
    5. 查询姓张或者姓李而且名字里带亭字的,正则应该这样写:/[张李].*亭{1,}.*/ 或者/[张李].*亭+.*/
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,175评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,674评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,151评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,597评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,505评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,969评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,455评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,118评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,227评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,213评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,214评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,928评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,512评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,616评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,848评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,228评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,772评论 2 339

推荐阅读更多精彩内容