配置Solr用于暗示/预测自动完成搜索

时间:2012-08-31 12:37:05

标签: search solr lucene search-suggestion

我们正在努力将Solr 3.6集成到电子商务网站。我们已将数据编入索引搜索表现非常好。

我们在如何使用Predictive Search / Auto Complete Search建议方面遇到一些困难。也有兴趣了解实现此功能的最佳实践。

我们的目标是提供类似于http://www.amazon.com/的预测搜索,但不知道如何使用Solr实现它。更具体地说,我想了解如何从Solr构建这些术语,还是由solr外部的其他东西管理?如何建立字典以提供这些建议?此外,对于某些领域,搜索应提供类别搜索。尝试在亚马逊搜索框中输入“xper”,你会注意到除了xperia,xperia s,xperia p之外,它还列出了手机和手机中的xperia s。配件,这是一个类别。

使用自定义词典时,这很难管理。或者我们可能不知道如何正确地做到这一点。期待您指导我们如何最好地利用solr来实现这种暗示搜索。

3 个答案:

答案 0 :(得分:7)

我建议你写一些博文:

  • This向您展示一个非常好的完整解决方案,该解决方案运行良好但需要进行一些额外的工作,并为特定目的使用特定的lucene索引(solr核心)

答案 1 :(得分:1)

我使用了Highlight方法,因为facet.prefix对于大索引而言太重了,而其他的文档很少或不清楚(我是一个愚蠢的程序员)

因此,我们假设用户刚刚输入了“aaa bbb ccc

我们的自动完成功能(java / javascript)将使用以下参数调用solr

q="aaa bbb"~100 ...base query, all the typed words except the last
fq=ccc* ...suggest word filter using last typed word
hl=true
hl.q=ccc* ...highlight word will be the one to suggest
fl=NONE ...return empty docs in result tag
hl.pre=### ...escape chars to locate highlight word in the response
hl.post=### ...see above

您还可以使用“rows”和“hl.fragsize”参数控制建议的数量

每个文档中的突出显示单词将是“aaa bbb”字符串

的建议的正确候选人

更多建议词是高亮词之前/之后的词,当然,你可以实现更多过滤器来提取有效词,避免重复,限制建议

如果有兴趣我可以给你发一些例子......

已编辑:有关该方法的更多详情

我给出的示例部分假设jquery给出的'autocomplete'机制:我们在Web应用程序中调用jsp(或servlet)作为请求参数传递'q'用户输入的单词。

这是jsp的代码

ByteArrayInputStream is=null; // Used to manage Solr response
try{

  StringBuffer queryUrl=new StringBuffer('putHereTheUrlOfSolrServer');
  queryUrl.append("/select?wt=xml");
  String typedWords=request.getParameter("q");
  String base="";
  if(typedWords.indexOf(" ")<=0) {
    // No space typed by user: the 'easy case'
    queryUrl.append("&q=text:");
    queryUrl.append(URLEncoder.encode(typedWords+"*", "UTF-8"));
    queryUrl.append("&hl.q=text:"+URLEncoder.encode(typedWords+"*", "UTF-8"));
   } else {
    // Space chars present
    // we split the search in base phrase and last typed word
    base=typedWords.substring(0,typedWords.lastIndexOf(" "));
    queryUrl.append("&q=text:");
    if(base.indexOf(" ")>0)
        queryUrl.append("\""+URLEncoder.encode(base, "UTF-8")+"\"~1000");
    else
        queryUrl.append(URLEncoder.encode(base, "UTF-8"));

    typedWords=typedWords.substring(typedWords.lastIndexOf(" ")+1);
    queryUrl.append("&fq=text:"+URLEncoder.encode(typedWords+"*", "UTF-8"));
    queryUrl.append("&hl.q=text:"+URLEncoder.encode(typedWords+"*", "UTF-8"));
}

  // The additional parameters to control the solr response
  queryUrl.append("&rows="+suggestPageSize); // Number of results returned, a parameter to control the number of suggestions
  queryUrl.append("&fl=A_FIELD_NAME_THAT_DOES_NOT_EXIST"); // Interested only in highlights section, Solr return a 'light' answer
  queryUrl.append("&start=0"); // Use only first page of results
  queryUrl.append("&hl=true"); // Enable highlights feature
  queryUrl.append("&hl.simple.pre=***"); // Use *** as 'highlight border'
  queryUrl.append("&hl.simple.post=***"); // Use *** as 'highlight border'
  queryUrl.append("&hl.fragsize="+suggestFragSize); // Another parameter to control the number of suggestions
  queryUrl.append("&hl.fl=content,title"); // Look for result only in some fields
  queryUrl.append("&facet=false"); // Disable facets

  /* Omitted section: use a new URL(queryUrl.toString()) to get the solr response inside a byte array */

  is=new ByteArrayInputStream(solrResponseByteArray);

  DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
  DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
  Document doc = dBuilder.parse(is);
  XPathFactory xPathfactory = XPathFactory.newInstance();
  XPath xpath = xPathfactory.newXPath();
  XPathExpression expr = xpath.compile("//response/lst[@name=\"highlighting\"]/lst/arr[@name=\"content\"]/str");
  NodeList valueList = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);

  Vector<String> suggestions=new Vector<String>();
  for (int j = 0; j < valueList.getLength(); ++j) {
     Element value = (Element) valueList.item(j);
     String[] result=value.getTextContent().split("\\*\\*\\*");
     for(int k=0;k<result.length;k++){
        String suggestedWord=result[k].toLowerCase();
        if((k%2)!=0){
             //Highlighted words management
             if(suggestedWord.length()>=suggestedWord.length() && !suggestions.contains(suggestedWord))
                 suggestions.add(suggestedWord);
        }else{
            /* Words before/after highlighted words
               we can put these words inside another vector
               and use them if not enough suggestions */
        }
     }
  }

  /* Finally we build a Json Answer to be managed by our jquery function */
  out.print(request.getParameter("json.wrf")+"({ \"suggestions\" : [");
  boolean firstSugg=true;       
  for(String suggestionW:suggestions) {
    out.print((firstSugg?" ":" ,"));
    out.print("{ \"suggest\" : \"");
    if(base.length()>0) {
        out.print(base);
        out.print(" ");
    }
    out.print(suggestionW+"\" }");
    firstSugg=false;
  }
  out.print(" ]})");
}catch (Exception x) {
  System.err.println("Exception during main process: " + x);
  x.printStackTrace();
}finally{
  //Gracefully close streams//
  try{is.close();}catch(Exception x){;}
}

希望有所帮助, NIK

答案 2 :(得分:0)

这可能会帮助你。我正在努力做到这一点。

http://solr.pl/en/2010/10/18/solr-and-autocomplete-part-1/