【问题标题】:Build query with different kind of terms for SolR为 SolR 构建具有不同类型术语的查询
【发布时间】:2014-03-20 17:18:27
【问题描述】:

我有一个可以通过 SolR 上的 url 查询执行搜索的 web 应用程序。

结果作为 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"

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

确切的术语:"Harlan Coben"

多个词:shakespeare harlan coben

多个混合词:shakespeare "harlan coben" coben or shakespear "harlan coben" or "harlan coben" coben

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

我应该如何进行?通过正则表达式?还是有其他方法?

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

更具体地说,所有这些字符都可以是 "@(!ùéàç"chinese/russian 或任何其他字符(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} 尝试了这个但没有用..

有什么想法吗?

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

感谢您的帮助!

【问题讨论】:

  • 那么如果包含空格的搜索字符串用双引号括起来,你不希望它被拆分?
  • 是的,我需要保留确切的术语,例如“harlan coben”,而不是两个不同的术语

标签: java regex solr lucene


【解决方案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");
    }
}

现在,关于 URL 的替换,请注意 URLEncoder 不是用于对 URL 组件进行编码,而是对 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

【讨论】:

  • 感谢您的帮助,这可能会有所帮助,但我的问题是使用上述不同类型的术语来定义查询
  • 是的,这就是我需要的!非常感谢您的帮助 !我在正则表达式中很糟糕大声笑我如何用每种类型的字符替换字符 [a-z] ?因为,这个词可能是中文或俄文,或者它可能包含一些特殊字符,如“(”或“-”。我还需要对每个词进行一些操作,我会找到如何做到这一点,但你能告诉我吗?这个正则表达式,我如何单独使用每个单词或精确表达式?它是否与组一起使用?例如,对于像“\”Harlan Coben\“coben”这样的输入,“harlan coben”可以是 m.group(1) 和 coben @987654331 @ ?
  • 对于所有字母,您可以使用\p{IsL} 而不是[a-z](在Java 字符串中将给出“\\p{IsL}”)。至于分离每个单词,你应该用单独的方法来做。如果匹配在引号之间,则删除引号并使用简单的.split("\\s+") 来获取不同的单词。
  • 再次感谢,您能看到我的编辑吗?我提供了更多细节和一个例子。在我这边,我会继续搜索和尝试,谢谢!
【解决方案2】:

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

如果搜索是这样的示例:

哈兰·科本“哈兰·科本”

找到的每个匹配项将是:

哈兰
科本
“哈伦·科本”

这里是使用的代码:

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 的另一件事,它需要转义一些特殊字符 + - && || ! ( ) { } [ ] ^ " ~ * ? : \ ,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();
    } 

现在它工作正常:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-06
    • 2012-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-02
    相关资源
    最近更新 更多