使用SolR的不同类型的术语构建查询

时间:2014-03-20 17:18:27

标签: java regex solr lucene

我有一个可以通过SolR上的url查询执行搜索的webapp。

结果作为Document对象接收。

我的查询看起来像:q=Book:Harlan AND Book:Coben AND ..,它运行正常。

String[] word = searchedWord.trim().split(" ");
for (int i = 0; i < word.length; i++) {
    if (!StringUtils.isEmpty(word[i])) {
        if (i > 0) {
            query.append("%20AND%20");
        } 
        String utf_encoded = URLEncoder.encode(StringEscapeUtils.escapeJava(word[i]), "UTF-8");
    }
}

但我需要强制执行搜索条件,因为当搜索的字词与确切的字词"Harlan Coben"完全相同时,此代码会将其分为两个字"HarlanCoben" < / p>

例如,我的webapp应该能够搜索:

确切条款:"Harlan Coben"

多个术语:shakespeare harlan coben

多个混合字词:shakespeare "harlan coben" cobenshakespear "harlan coben""harlan coben" coben

调用SolR的URL以UTF-8编码,以替换特殊字符..

我该怎么办?通过正则表达式?还是有另一种方式?

------编辑--------

更具体一点,所有这些字符都可以是“@(!ùéàç”中文/俄文或其他任何字符(unicode?)来自特定语言

我需要匹配它们并将它们分开以准备SolR查询。

示例:

如果搜索字词为:coben "Harlan Coben" s(554603)hakesdpeare Straße Привет 我的正则表达式应该匹配并给我这个结果:

 coben
 "Harlan Coben"
 s(554603)hakesdpeare
 Straße
 Привет

然后我需要使用AND Book:或juste Book:将它们连接起来,以获得如下查询:

q=Book:coben AND Book:"Harlan Coben" AND Book:s(554603)hakesdpeare AND Book:Straße AND Book:Привет

我从@fge尝试("[a-z]+(?:\s+[a-z]+)+"|[a-z]+)(?:\s+|$)(感谢您),但它只与[a-z]匹配,我尝试使用\\p{all}但是没有效果..

有什么想法吗?

------结束编辑--------

感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

你可以使用正则表达式,但它会非常复杂;在这种情况下,您需要更改。这里假设您的搜索字词只有字母:

("[a-z]+(?:\s+[a-z]+)+"|[a-z]+)(?:\s+|$)

(请注意,交替顺序重要在这里!)

示例:

public final class Bar
{
    private static final Pattern PATTERN = Pattern
        .compile("(\"[a-z]+(?:\\s+[a-z]+)+\"|[a-z]+)(?:\\s+|$)",
            Pattern.CASE_INSENSITIVE);

    public static void main(final String... args)
        throws IOException
    {
        tryAndMatch("\"Harlan Coben\"");
        tryAndMatch("shakespeare harlan coben");
        tryAndMatch("shakespeare \"harlan coben\" coben");
    }

    private static void tryAndMatch(final String input)
    {
        final Matcher m = PATTERN.matcher(input);

        System.out.printf("INPUT: -->%s<--\n", input);

        while (m.find())
            System.out.printf("Term -->%s<--\n", m.group(1));

        System.out.println("END INPUT");
    }
}

现在,关于替换为网址,请注意URLEncoder而不是对网址组件进行编码,它会对application/x-www-form-urlencoded数据进行编码,其中包含空格变为+并且没有与URI路径或片段相同的转义字符集。

最准确的解决方案是使用URI模板。这允许您编写模板,例如:

http://my.site/?q={query}

其中query是任何Unicode字符串,这将为您编码(自我推销:如果您感兴趣,我有一个library to do that)。

第二种是使用Guava 15.0+,它有一个set of escapers especially made for URLs

答案 1 :(得分:0)

我终于找到了正确的正则表达式来匹配任何字符(包括中文或其他语言)并给我每个搜索词:

搜索示例如下:

  

harlan coben“harlan coben”

找到的每个匹配将是:

  哈朗
  coben
“哈伦科本”

以下是使用过的代码:

Pattern PATTERN = Pattern.compile("(?>\"[^\"]+\"+)|(?>[^ ]+)+");
Matcher match = PATTERN.matcher(motRecherche);
match.reset();
int iM = 0;

while(match.find()){
    if(iM > 0){
        query.append("%20AND%20");
    }

    String utf_encoded = CommonUtils.escapeSolrQuery(match.group(0));
    query.append(":"+utf_encoded);
    iM++;
}

关于SolR的另一件事,它需要逃避一些特殊字符 + - &amp;&amp; || ! (){} [] ^“〜*?:\ ,SolR提供了一个名为ClientUtils的客户端类和一个我为我改变的方法escapeQueryChars():

public static String escapeSolrQuery(String searchWord){

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < searchWord.length(); i++) {
          char c = searchWord.charAt(i);

          if (c == '\\' || c == '+' || c == '-' || c == '!'  || c == '(' || c == ')' || c == ':'
            || c == '^' || c == '[' || c == ']' || c == '{' || c == '}' || c == '~'
            || c == '*' || c == '?' || c == '|' || c == '&'  || c == ';' || c == '/') 
          {
            sb.append('\\');
          }

          if(c == '\"' && !searchWord.matches("\"[^\"]+\"")){
              sb.append('\\');
          }
          sb.append(c);
        }
       return sb.toString();
    } 

现在它可以正常工作:)