Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 正则表达式中的性能问题_Java_Regex_Optimization_Pattern Matching_Matcher - Fatal编程技术网

Java 正则表达式中的性能问题

Java 正则表达式中的性能问题,java,regex,optimization,pattern-matching,matcher,Java,Regex,Optimization,Pattern Matching,Matcher,我有我的REST服务,它在重载下运行,这意味着它每天会收到大约一百万个读取呼叫的大量流量。我的REST服务将根据用户ID从数据库中进行查找,并检索与该用户ID对应的几列 因此,我目前在代码中看到了高性能问题。我怀疑下面的方法将是我应该首先开始优化的方法之一 下面的方法将接受一个attributeName,然后在此基础上使用正则表达式为我提供匹配 让我们举个例子——如果attrName是technology.profile.financial 然后,下面的方法将以technology.profil

我有我的REST服务,它在重载下运行,这意味着它每天会收到大约一百万个读取呼叫的大量流量。我的REST服务将根据用户ID从数据库中进行查找,并检索与该用户ID对应的几列

因此,我目前在代码中看到了高性能问题。我怀疑下面的方法将是我应该首先开始优化的方法之一

下面的方法将接受一个
attributeName
,然后在此基础上使用正则表达式为我提供匹配

让我们举个例子——如果
attrName
technology.profile.financial

然后,下面的方法将以
technology.profile
的形式返回我。这种方法也适用于其他情况

private String getAttrDomain(String attrName){
    Pattern r = Pattern.compile(CommonConstants.VALID_DOMAIN);
    Matcher m = r.matcher(attrName.toLowerCase());
    if (m.find()) {
      return m.group(0);
    }
    return null;
}
CommonConstants
类文件中

String  VALID_DOMAIN = "(technology|computer|sdc|adj|wdc|pp|stub).(profile|preference|experience|behavioral)";
我只是想看看,这里是否有一些性能问题,或者不使用上面的正则表达式?如果是的话,那么在考虑性能问题的情况下,重新编写此内容的最佳方法是什么


谢谢你的帮助。

我用卡钳测试了这个和这个,结果是:如果你在每次方法调用之前编译模式,这将是最快的方法

正则表达式方法是最快的方法,但他唯一需要做的改变是 预先计算模式,而不是每次:

 private static Pattern p = Pattern.compile(VALID_DOMAIN);
然后在您的方法中:

 Matcher matcher = pattern.matcher(input); ...
对于感兴趣的人来说,这是我用于卡尺的设置:--warmupMillis 10000--runMillis 100

 package stackoverflow;

 import java.util.regex.Matcher;
 import java.util.regex.Pattern;

 import com.google.caliper.Param;
 import com.google.caliper.Runner;
 import com.google.caliper.SimpleBenchmark;
 import com.google.common.base.Splitter;
 import com.google.common.collect.Iterables;

 public class RegexPerformance extends SimpleBenchmark {
      private static final String firstPart    = "technology|computer|sdc|adj|wdc|pp|stub";
      private static final String secondPart   = "profile|preference|experience|behavioral";
      private static final String VALID_DOMAIN = "(technology|computer|sdc|adj|wdc|pp|stub)\\.(profile|preference|experience|behavioral)";

      @Param({"technology.profile.financial", "computer.preference.test","sdc.experience.test"})
      private String input;

      public static void main(String[] args) {
           Runner.main(RegexPerformance.class, args);
      }

      public void timeRegexMatch(int reps){
          for(int i=0;i<reps;++i){
              regexMatch(input);
          }
      }


      public void timeGuavaMatch(int reps){
          for(int i=0;i<reps;++i){
              guavaMatch(input);
          }
      }

      public void timeRegexMatchOutsideMethod(int reps){
          for(int i=0;i<reps;++i){
              regexMatchOutsideMethod(input);
          }
      }


    public String regexMatch(String input){
        Pattern p = Pattern.compile(VALID_DOMAIN);
        Matcher m = p.matcher(input);
        if(m.find()) return m.group();
        return null;
    }

    public String regexMatchOutsideMethod(String input){
          Matcher matcher = pattern.matcher(input);
          if(matcher.find()) return matcher.group();
          return null;
    }

    public String guavaMatch(String input){
        Iterable<String> tokens = Splitter.on(".").omitEmptyStrings().split(input);
        String firstToken  = Iterables.get(tokens, 0);
        String secondToken = Iterables.get(tokens, 1);
        if( (firstPart.contains(firstToken) ) && (secondPart.contains(secondToken)) ){
            return firstToken+"."+secondToken;
        }
        return null;
    }
}
两点:

正如注释中提到的,除了在函数外部编译表达式外,还可以使
()
不捕获,这样就不会保存每个函数匹配的内容,即

String  VALID_DOMAIN = "(?:technology|computer|sdc|adj|wdc|pp|stub)\\.(?:profile|preference|experience|behavioral)";
如果有效域必须始终出现在属性名称的开头,您可以使用
lookingAt
方法而不是
find
,这样匹配会更快失败,即

 if (m.lookingAt()) {

如果表达式是在函数外部编译的,您可以添加
模式。不区分大小写
,这样您就不必每次在
attrName
上调用
toLowerCase()

有什么原因不能将正则表达式保存为模式而不是字符串?如果regex从未更改,那么每次使用它时都会浪费大量时间重新编译regex。对于这样一个简单的模式,编译正则表达式可能比实际匹配要花费更多的时间

至于正则表达式本身,我建议进行一些更改。这些更改将使正则表达式稍微更有效率,但可能还不足以引起注意。目的是使其更加健壮

  • 将其括在单词边界中,以避免字符串出现误报,如
    foo\u technology.profile
    technology.profile\u bar
    。我相信你知道在你的情况下会发生这样的事情,但是为什么要冒这么小的风险呢
  • 避开圆点,如图所示
  • 使用非捕获组而不是捕获组。(假设您实际上不需要分解属性名的各个组件。)


只是说,但是
匹配任何字符。如果要匹配实际的
,必须将其转义。是否确定性能问题是与regex有关,而不是与数据库有关?否,不是与数据库有关。我在每个组件级别都安装了仪器。所以在数据库方面,它看起来不错。但只有在这个部分,我看到了很多变化。在这个类中,我知道一个问题可能是多线程,但另一个问题我怀疑这个正则表达式匹配。这就是我想确定使用类regex是否会导致性能下降的原因。@Farhan尝试一个粗糙的
System.nanoTime()
benchmark?转义
。表达式本身没有任何性能问题。尝试在函数之外编译表达式,而不是在每次函数调用中编译表达式。您是否故意拼写错误
sdc.experince.test
以测试不匹配项,或者这只是一个输入错误?我想给您一个优雅的解决方法。;)真的应该至少有一次考试不及格,你不觉得吗?特别是涉及正则表达式时;通常在失败的比赛尝试中,你会看到巨大的表现惩罚。@Alanmore当我再仔细想想时,我认为你是对的。威尔也加入了他们。thx@Eugene,我猜,您没有在实际代码中将模式声明为静态。@FarhanJamal darn您是对的:),但它很简单-->private static final Pattern patter=new Pattern(VALID_DOMAIN);谢谢迈克的建议。唯一的问题是我不知道如何使用
模式。这里不区分大小写
?你能提供一个关于我的场景的例子吗?谢谢你的帮助。@FarhanJamal<代码>模式r=Pattern.compile(CommonConstants.VALID\u域,Pattern.CASE\u不区分大小写)
 if (m.lookingAt()) {
static final Pattern VALID_DOMAIN_PATTERN = Pattern.compile(
    "\\b(?:technology|computer|sdc|adj|wdc|pp|stub)\\.(?:profile|preference|experience|behavioral)\\b");