Elasticsearch:正确使用regexp搜索

Regular Expressions 搜索也即正则搜索是非常耗时的。正则表达式是一种使用placeholder(称为运算符)匹配数据中的模式的方法。 有关regexp查询支持的运算符的列表,请参阅 Regular expression syntax

在今天的文章中,我们来简单介绍如何正确使用regexp搜索。

正则表达式语法中使用了许多符号和运算符来表示通配符和字符范围:

  • 句号“.” 用于代表任何字符。
  • 用括号括起来的一系列字符,例如[a-z],是一个字符类。 字符类表示字符范围; 在此示例中,它充当任何字母的替代。
  • 加号“ +”用于表示重复的字符; 例如,“Mississippi”中的“ pp”。

我们来看一个“regexp”,其中包含我们刚刚讨论的所有正则表达式语法。 以下示例中显示的regexp将与单词“ Mississippi”匹配:

GET states/_search
{
  "query": {
    "regexp": {
      "name": "[a-z]*ip+i"
    }
  }
}

# RETURNS --->
"name" : "Mississippi"


GET states/_search
{
  "query": {
    "regexp": {
      "name": "mis+[a-z]*"
    }
  }
}
# RETURNS --->
"name" : "Missouri"
# ..and
"name" : "Mississippi"

GET states/_search
{
  "query": {
    "regexp": {
      "name": "[a-z]*ska"
    }
  }
}

# RETURNS -->
"name" : "Alaska"
# and..
"name" : "Nebraska"

我们首先创建一个my_example的索引:

PUT my_example/_doc/1
{
  "content": "This is a good network"
}

假如我们想搜索以net为开头的文档,那么我们可以使用regexp来进行如下写的搜索:

GET my_example/_search
{
  "query": {
    "regexp": {
      "content": "net.*"
    }
  }
}

根据Regular expression syntax里的描述,它匹配任何以net为开头的所有的文档:

可能有人想搜索以work结束的术语的所有文档,那么我们应该怎么做呢?我们可以通过如下的方法:

GET my_example/_search
{
  "query": {
    "regexp": {
      "content": ".*work"
    }
  }
}

显示的结果为:

我们得到了我们希望的结果。

虽然在上面我们得到我们想要的结果,但是在实际使用regexp搜索时,我们必须记住如下的事项:

  • 避免通配符在前面,比如上面的.*work。可能以避免使用前导通配符的方式对数据建立索引
  • 通常,正则表达式可能会很昂贵

那么什么是正确的解决方案呢?

如果您确实需要匹配token的末尾,只需使用reverse过滤器为它们建立索引。下面,我们用一个具体的例子来实现。

首先,我们为reverse_example建立一个mapping:

PUT reverse_example
{
  "settings": {
    "analysis": {
      "analyzer": {
        "whitespace_reverse": {
          "tokenizer": "whitespace",
          "filter": [
            "reverse"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "content": {
        "type": "text",
        "fields": {
          "reversed": {
            "type": "text",
            "analyzer": "whitespace_reverse"
          }
        }
      }
    }
  }
}

在这里content是一个multi-field的字段。content.reversed将使用whitespace_reverse分析器来对我们的字段进行分词。这个分析器将会对术语进行倒序处理。比如:

GET reverse_example/_analyze
{
  "tokenizer": "standard",
  "filter": [
    "reverse"
  ],
  "text": "quick fox jumps"
}

它将返回:

{
  "tokens" : [
    {
      "token" : "kciuq",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "<ALPHANUM>",
      "position" : 0
    },
    {
      "token" : "xof",
      "start_offset" : 6,
      "end_offset" : 9,
      "type" : "<ALPHANUM>",
      "position" : 1
    },
    {
      "token" : "spmuj",
      "start_offset" : 10,
      "end_offset" : 15,
      "type" : "<ALPHANUM>",
      "position" : 2
    }
  ]
}

现在,我们对我们的索引添加一个文档:

PUT reverse_example/_doc/1
{
  "content": "This is a good network"
}

 那么我们对我们的文档重新使用regexp进行搜索:

GET reverse_example/_search
{
  "query": {
    "regexp": {
      "content.reversed": "krow.*"
    }
  }
}

显示的结果为:

我们通过上面的方法把通配符在前面的搜索修改成为通配符在后面的regexp搜索。

参考:

【1】https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-reverse-tokenfilter.html

发布了489 篇原创文章 · 获赞 107 · 访问量 84万+

猜你喜欢

转载自blog.csdn.net/UbuntuTouch/article/details/104136035