| 1 | <%-- | 
|---|
| 2 |   Licensed to the Apache Software Foundation (ASF) under one or more | 
|---|
| 3 |   contributor license agreements.  See the NOTICE file distributed with | 
|---|
| 4 |   this work for additional information regarding copyright ownership. | 
|---|
| 5 |   The ASF licenses this file to You under the Apache License, Version 2.0 | 
|---|
| 6 |   (the "License"); you may not use this file except in compliance with | 
|---|
| 7 |   the License.  You may obtain a copy of the License at | 
|---|
| 8 |    | 
|---|
| 9 |   http://www.apache.org/licenses/LICENSE-2.0 | 
|---|
| 10 |    | 
|---|
| 11 |   Unless required by applicable law or agreed to in writing, software | 
|---|
| 12 |   distributed under the License is distributed on an "AS IS" BASIS, | 
|---|
| 13 |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|---|
| 14 |   See the License for the specific language governing permissions and | 
|---|
| 15 |   limitations under the License. | 
|---|
| 16 | --%> | 
|---|
| 17 | <%@ page  | 
|---|
| 18 |   session="false" | 
|---|
| 19 |   contentType="text/html; charset=UTF-8" | 
|---|
| 20 |   pageEncoding="UTF-8" | 
|---|
| 21 |  | 
|---|
| 22 |   import="java.io.*" | 
|---|
| 23 |   import="java.util.*" | 
|---|
| 24 |   import="java.net.*" | 
|---|
| 25 |   import="javax.servlet.http.*" | 
|---|
| 26 |   import="javax.servlet.*" | 
|---|
| 27 |  | 
|---|
| 28 |   import="org.apache.nutch.html.Entities" | 
|---|
| 29 |   import="org.apache.nutch.metadata.Nutch" | 
|---|
| 30 |   import="org.apache.nutch.searcher.*" | 
|---|
| 31 |   import="org.apache.nutch.plugin.*" | 
|---|
| 32 |   import="org.apache.nutch.clustering.*" | 
|---|
| 33 |   import="org.apache.hadoop.conf.*" | 
|---|
| 34 |   import="org.apache.nutch.util.NutchConfiguration" | 
|---|
| 35 | %><%! | 
|---|
| 36 |   /** | 
|---|
| 37 |    * Number of hits to retrieve and cluster if clustering extension is available | 
|---|
| 38 |    * and clustering is on. By default, 100. Configurable via nutch-conf.xml. | 
|---|
| 39 |    */ | 
|---|
| 40 |   private int HITS_TO_CLUSTER; | 
|---|
| 41 |  | 
|---|
| 42 |   /** | 
|---|
| 43 |    * Maximum hits per page to be displayed. | 
|---|
| 44 |    */ | 
|---|
| 45 |   private int MAX_HITS_PER_PAGE; | 
|---|
| 46 |  | 
|---|
| 47 |   /** | 
|---|
| 48 |    * An instance of the clustering extension, if available. | 
|---|
| 49 |    */ | 
|---|
| 50 |   private OnlineClusterer clusterer; | 
|---|
| 51 |    | 
|---|
| 52 |   /** | 
|---|
| 53 |    * Nutch configuration for this servlet. | 
|---|
| 54 |    */ | 
|---|
| 55 |   private Configuration nutchConf; | 
|---|
| 56 |  | 
|---|
| 57 |   /** | 
|---|
| 58 |    * Initialize search bean. | 
|---|
| 59 |    */ | 
|---|
| 60 |   public void jspInit() { | 
|---|
| 61 |     super.jspInit(); | 
|---|
| 62 |      | 
|---|
| 63 |     final ServletContext application = getServletContext();  | 
|---|
| 64 |     nutchConf = NutchConfiguration.get(application); | 
|---|
| 65 |     HITS_TO_CLUSTER = nutchConf.getInt("extension.clustering.hits-to-cluster", 100); | 
|---|
| 66 |     MAX_HITS_PER_PAGE = nutchConf.getInt("searcher.max.hits.per.page", -1); | 
|---|
| 67 |  | 
|---|
| 68 |     try { | 
|---|
| 69 |       clusterer = new OnlineClustererFactory(nutchConf).getOnlineClusterer(); | 
|---|
| 70 |     } catch (PluginRuntimeException e) { | 
|---|
| 71 |       super.log("Could not initialize online clusterer: " + e.toString()); | 
|---|
| 72 |     } | 
|---|
| 73 |   } | 
|---|
| 74 | %> | 
|---|
| 75 |  | 
|---|
| 76 | <%-- | 
|---|
| 77 | // Uncomment this to enable query refinement. | 
|---|
| 78 | // Do the same to "refine-query.jsp" below., | 
|---|
| 79 | <%@ include file="./refine-query-init.jsp" %> | 
|---|
| 80 | --%> | 
|---|
| 81 |  | 
|---|
| 82 | <% | 
|---|
| 83 |   // The Nutch bean instance is initialized through a ServletContextListener  | 
|---|
| 84 |   // that is setup in the web.xml file | 
|---|
| 85 |   NutchBean bean = NutchBean.get(application, nutchConf); | 
|---|
| 86 |   // set the character encoding to use when interpreting request values  | 
|---|
| 87 |   request.setCharacterEncoding("UTF-8"); | 
|---|
| 88 |  | 
|---|
| 89 |   bean.LOG.info("query request from " + request.getRemoteAddr()); | 
|---|
| 90 |  | 
|---|
| 91 |   // get query from request | 
|---|
| 92 |   String queryString = request.getParameter("query"); | 
|---|
| 93 |   if (queryString == null) | 
|---|
| 94 |     queryString = ""; | 
|---|
| 95 |   String htmlQueryString = Entities.encode(queryString); | 
|---|
| 96 |    | 
|---|
| 97 |   // a flag to make the code cleaner a bit. | 
|---|
| 98 |   boolean clusteringAvailable = (clusterer != null); | 
|---|
| 99 |  | 
|---|
| 100 |   String clustering = ""; | 
|---|
| 101 |   if (clusteringAvailable && "yes".equals(request.getParameter("clustering"))) | 
|---|
| 102 |     clustering = "yes"; | 
|---|
| 103 |  | 
|---|
| 104 |   int start = 0;          // first hit to display | 
|---|
| 105 |   String startString = request.getParameter("start"); | 
|---|
| 106 |   if (startString != null) | 
|---|
| 107 |     start = Integer.parseInt(startString); | 
|---|
| 108 |  | 
|---|
| 109 |   int hitsPerPage = 10;          // number of hits to display | 
|---|
| 110 |   String hitsString = request.getParameter("hitsPerPage"); | 
|---|
| 111 |   if (hitsString != null) | 
|---|
| 112 |     hitsPerPage = Integer.parseInt(hitsString); | 
|---|
| 113 |   if(MAX_HITS_PER_PAGE > 0 && hitsPerPage > MAX_HITS_PER_PAGE) | 
|---|
| 114 |     hitsPerPage = MAX_HITS_PER_PAGE; | 
|---|
| 115 |  | 
|---|
| 116 |   int hitsPerSite = 2;                            // max hits per site | 
|---|
| 117 |   String hitsPerSiteString = request.getParameter("hitsPerSite"); | 
|---|
| 118 |   if (hitsPerSiteString != null) | 
|---|
| 119 |     hitsPerSite = Integer.parseInt(hitsPerSiteString); | 
|---|
| 120 |  | 
|---|
| 121 |   String sort = request.getParameter("sort"); | 
|---|
| 122 |   boolean reverse = | 
|---|
| 123 |     sort!=null && "true".equals(request.getParameter("reverse")); | 
|---|
| 124 |  | 
|---|
| 125 |   String params = "&hitsPerPage="+hitsPerPage | 
|---|
| 126 |      +(sort==null ? "" : "&sort="+sort+(reverse?"&reverse=true":"")); | 
|---|
| 127 |  | 
|---|
| 128 |   int hitsToCluster = HITS_TO_CLUSTER;            // number of hits to cluster | 
|---|
| 129 |  | 
|---|
| 130 |   // get the lang from request | 
|---|
| 131 |   String queryLang = request.getParameter("lang"); | 
|---|
| 132 |   if (queryLang == null) { queryLang = ""; } | 
|---|
| 133 |   Query query = Query.parse(queryString, queryLang, nutchConf); | 
|---|
| 134 |   bean.LOG.info("query: " + queryString); | 
|---|
| 135 |   bean.LOG.info("lang: " + queryLang); | 
|---|
| 136 |  | 
|---|
| 137 |   String language = | 
|---|
| 138 |     ResourceBundle.getBundle("org.nutch.jsp.search", request.getLocale()) | 
|---|
| 139 |     .getLocale().getLanguage(); | 
|---|
| 140 |   String requestURI = HttpUtils.getRequestURL(request).toString(); | 
|---|
| 141 |   String base = requestURI.substring(0, requestURI.lastIndexOf('/')); | 
|---|
| 142 |   String rss = "../opensearch?query="+htmlQueryString | 
|---|
| 143 |     +"&hitsPerSite="+hitsPerSite+"&lang="+queryLang+params; | 
|---|
| 144 | %><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> | 
|---|
| 145 | <% | 
|---|
| 146 |   // To prevent the character encoding declared with 'contentType' page | 
|---|
| 147 |   // directive from being overriden by JSTL (apache i18n), we freeze it | 
|---|
| 148 |   // by flushing the output buffer.  | 
|---|
| 149 |   // see http://java.sun.com/developer/technicalArticles/Intl/MultilingualJSP/ | 
|---|
| 150 |   out.flush(); | 
|---|
| 151 | %> | 
|---|
| 152 | <%@ taglib uri="http://jakarta.apache.org/taglibs/i18n" prefix="i18n" %> | 
|---|
| 153 | <i18n:bundle baseName="org.nutch.jsp.search"/> | 
|---|
| 154 | <html lang="<%= language %>"> | 
|---|
| 155 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> | 
|---|
| 156 | <head> | 
|---|
| 157 | <title>Nutch: <i18n:message key="title"/></title> | 
|---|
| 158 | <link rel="icon" href="img/favicon.ico" type="image/x-icon"/> | 
|---|
| 159 | <link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon"/> | 
|---|
| 160 | <link rel="alternate" type="application/rss+xml" title="RSS" href="<%=rss%>"/> | 
|---|
| 161 | <jsp:include page="include/style.html"/> | 
|---|
| 162 | <base href="<%= base  + "/" + language %>/"> | 
|---|
| 163 | <script type="text/javascript"> | 
|---|
| 164 | <!-- | 
|---|
| 165 | function queryfocus() { document.search.query.focus(); } | 
|---|
| 166 | // --> | 
|---|
| 167 | </script> | 
|---|
| 168 | </head> | 
|---|
| 169 |  | 
|---|
| 170 | <body onLoad="queryfocus();"> | 
|---|
| 171 |  | 
|---|
| 172 | <jsp:include page="<%= language + \"/include/header.html\"%>"/> | 
|---|
| 173 |  | 
|---|
| 174 |  <form name="search" action="../search.jsp" method="get"> | 
|---|
| 175 |  <input name="query" size=44 value="<%=htmlQueryString%>"> | 
|---|
| 176 |  <input type="hidden" name="hitsPerPage" value="<%=hitsPerPage%>"> | 
|---|
| 177 |  <input type="hidden" name="lang" value="<%=language%>"> | 
|---|
| 178 |  <input type="submit" value="<i18n:message key="search"/>"> | 
|---|
| 179 |  <% if (clusteringAvailable) { %> | 
|---|
| 180 |    <input id="clustbox" type="checkbox" name="clustering" value="yes" <% if (clustering.equals("yes")) { %>CHECKED<% } %>> | 
|---|
| 181 |     <label for="clustbox"><i18n:message key="clustering"/></label> | 
|---|
| 182 |  <% } %> | 
|---|
| 183 |  <a href="help.html">help</a> | 
|---|
| 184 |  </form> | 
|---|
| 185 |  | 
|---|
| 186 | <%-- | 
|---|
| 187 | // Uncomment this to enable query refinement. | 
|---|
| 188 | // Do the same to "refine-query-init.jsp" above. | 
|---|
| 189 | <%@ include file="./refine-query.jsp" %> | 
|---|
| 190 | --%> | 
|---|
| 191 |  | 
|---|
| 192 | <% | 
|---|
| 193 |    // how many hits to retrieve? if clustering is on and available, | 
|---|
| 194 |    // take "hitsToCluster", otherwise just get hitsPerPage | 
|---|
| 195 |    int hitsToRetrieve = (clusteringAvailable && clustering.equals("yes") ? hitsToCluster : hitsPerPage); | 
|---|
| 196 |  | 
|---|
| 197 |    if (clusteringAvailable && clustering.equals("yes")) { | 
|---|
| 198 |      bean.LOG.info("Clustering is on, hits to retrieve: " + hitsToRetrieve); | 
|---|
| 199 |    } | 
|---|
| 200 |  | 
|---|
| 201 |    // perform query | 
|---|
| 202 |     // NOTE by Dawid Weiss: | 
|---|
| 203 |     // The 'clustering' window actually moves with the start | 
|---|
| 204 |     // position.... this is good, bad?... ugly?.... | 
|---|
| 205 |    Hits hits; | 
|---|
| 206 |    try{ | 
|---|
| 207 |      hits = bean.search(query, start + hitsToRetrieve, hitsPerSite, "site", | 
|---|
| 208 |                         sort, reverse); | 
|---|
| 209 |    } catch (IOException e){ | 
|---|
| 210 |      hits = new Hits(0,new Hit[0]);  | 
|---|
| 211 |    } | 
|---|
| 212 |    int end = (int)Math.min(hits.getLength(), start + hitsPerPage); | 
|---|
| 213 |    int length = end-start; | 
|---|
| 214 |    int realEnd = (int)Math.min(hits.getLength(), start + hitsToRetrieve); | 
|---|
| 215 |  | 
|---|
| 216 |    Hit[] show = hits.getHits(start, realEnd-start); | 
|---|
| 217 |    HitDetails[] details = bean.getDetails(show); | 
|---|
| 218 |    Summary[] summaries = bean.getSummary(details, query); | 
|---|
| 219 |    bean.LOG.info("total hits: " + hits.getTotal()); | 
|---|
| 220 | %> | 
|---|
| 221 |  | 
|---|
| 222 | <i18n:message key="hits"> | 
|---|
| 223 |   <i18n:messageArg value="<%=new Long((end==0)?0:(start+1))%>"/> | 
|---|
| 224 |   <i18n:messageArg value="<%=new Long(end)%>"/> | 
|---|
| 225 |   <i18n:messageArg value="<%=new Long(hits.getTotal())%>"/> | 
|---|
| 226 | </i18n:message> | 
|---|
| 227 |  | 
|---|
| 228 | <% | 
|---|
| 229 | // be responsive | 
|---|
| 230 | out.flush(); | 
|---|
| 231 | %> | 
|---|
| 232 |  | 
|---|
| 233 | <br><br> | 
|---|
| 234 |  | 
|---|
| 235 | <% if (clustering.equals("yes") && length != 0) { %> | 
|---|
| 236 | <table border=0 cellspacing="3" cellpadding="0"> | 
|---|
| 237 |  | 
|---|
| 238 | <tr> | 
|---|
| 239 |  | 
|---|
| 240 | <td valign="top"> | 
|---|
| 241 |  | 
|---|
| 242 | <% } %> | 
|---|
| 243 |  | 
|---|
| 244 | <% | 
|---|
| 245 |   for (int i = 0; i < length; i++) {      // display the hits | 
|---|
| 246 |     Hit hit = show[i]; | 
|---|
| 247 |     HitDetails detail = details[i]; | 
|---|
| 248 |     String title = detail.getValue("title"); | 
|---|
| 249 |     String url = detail.getValue("url"); | 
|---|
| 250 |     String id = "idx=" + hit.getIndexNo() + "&id=" + hit.getUniqueKey(); | 
|---|
| 251 |     String summary = summaries[i].toHtml(true); | 
|---|
| 252 |     String caching = detail.getValue("cache"); | 
|---|
| 253 |     boolean showSummary = true; | 
|---|
| 254 |     boolean showCached = true; | 
|---|
| 255 |     if (caching != null) { | 
|---|
| 256 |       showSummary = !caching.equals(Nutch.CACHING_FORBIDDEN_ALL); | 
|---|
| 257 |       showCached = !caching.equals(Nutch.CACHING_FORBIDDEN_NONE); | 
|---|
| 258 |     } | 
|---|
| 259 |  | 
|---|
| 260 |     if (title == null || title.equals("")) {      // use url for docs w/o title | 
|---|
| 261 |       title = url; | 
|---|
| 262 |     } | 
|---|
| 263 |     %> | 
|---|
| 264 |     <b><a href="<%=url%>"><%=Entities.encode(title)%></a></b> | 
|---|
| 265 |     <%@ include file="more.jsp" %> | 
|---|
| 266 |     <% if (!"".equals(summary) && showSummary) { %> | 
|---|
| 267 |     <br><%=summary%> | 
|---|
| 268 |     <% } %> | 
|---|
| 269 |     <br> | 
|---|
| 270 |     <span class="url"><%=Entities.encode(url)%></span> | 
|---|
| 271 |     <% | 
|---|
| 272 |       if (showCached) { | 
|---|
| 273 |         %>(<a href="../cached.jsp?<%=id%>"><i18n:message key="cached"/></a>) <% | 
|---|
| 274 |     } | 
|---|
| 275 |     %> | 
|---|
| 276 |     (<a href="../explain.jsp?<%=id%>&query=<%=URLEncoder.encode(queryString, "UTF-8")%>&lang=<%=queryLang%>"><i18n:message key="explain"/></a>) | 
|---|
| 277 |     (<a href="../anchors.jsp?<%=id%>"><i18n:message key="anchors"/></a>) | 
|---|
| 278 |     <% if (hit.moreFromDupExcluded()) { | 
|---|
| 279 |     String more = | 
|---|
| 280 |     "query="+URLEncoder.encode("site:"+hit.getDedupValue()+" "+queryString, "UTF8") | 
|---|
| 281 |     +params+"&hitsPerSite="+0 | 
|---|
| 282 |     +"&lang="+queryLang | 
|---|
| 283 |     +"&clustering="+clustering;%> | 
|---|
| 284 |     (<a href="../search.jsp?<%=more%>"><i18n:message key="moreFrom"/> | 
|---|
| 285 |      <%=hit.getDedupValue()%></a>) | 
|---|
| 286 |     <% } %> | 
|---|
| 287 |     <br><br> | 
|---|
| 288 | <% } %> | 
|---|
| 289 |  | 
|---|
| 290 | <% if (clustering.equals("yes") && length != 0) { %> | 
|---|
| 291 |  | 
|---|
| 292 | </td> | 
|---|
| 293 |  | 
|---|
| 294 | <!-- clusters --> | 
|---|
| 295 | <td style="border-right: 1px dotted gray;" /> </td> | 
|---|
| 296 | <td align="left" valign="top" width="25%"> | 
|---|
| 297 | <%@ include file="cluster.jsp" %> | 
|---|
| 298 | </td> | 
|---|
| 299 |  | 
|---|
| 300 | </tr> | 
|---|
| 301 | </table> | 
|---|
| 302 |  | 
|---|
| 303 | <% } %> | 
|---|
| 304 |  | 
|---|
| 305 | <% | 
|---|
| 306 |  | 
|---|
| 307 | if ((hits.totalIsExact() && end < hits.getTotal()) // more hits to show | 
|---|
| 308 |     || (!hits.totalIsExact() && (hits.getLength() > start+hitsPerPage))) { | 
|---|
| 309 | %> | 
|---|
| 310 |     <form name="next" action="../search.jsp" method="get"> | 
|---|
| 311 |     <input type="hidden" name="query" value="<%=htmlQueryString%>"> | 
|---|
| 312 |     <input type="hidden" name="lang" value="<%=queryLang%>"> | 
|---|
| 313 |     <input type="hidden" name="start" value="<%=end%>"> | 
|---|
| 314 |     <input type="hidden" name="hitsPerPage" value="<%=hitsPerPage%>"> | 
|---|
| 315 |     <input type="hidden" name="hitsPerSite" value="<%=hitsPerSite%>"> | 
|---|
| 316 |     <input type="hidden" name="clustering" value="<%=clustering%>"> | 
|---|
| 317 |     <input type="submit" value="<i18n:message key="next"/>"> | 
|---|
| 318 | <% if (sort != null) { %> | 
|---|
| 319 |     <input type="hidden" name="sort" value="<%=sort%>"> | 
|---|
| 320 |     <input type="hidden" name="reverse" value="<%=reverse%>"> | 
|---|
| 321 | <% } %> | 
|---|
| 322 |     </form> | 
|---|
| 323 | <% | 
|---|
| 324 |     } | 
|---|
| 325 |  | 
|---|
| 326 | if ((!hits.totalIsExact() && (hits.getLength() <= start+hitsPerPage))) { | 
|---|
| 327 | %> | 
|---|
| 328 |     <form name="showAllHits" action="../search.jsp" method="get"> | 
|---|
| 329 |     <input type="hidden" name="query" value="<%=htmlQueryString%>"> | 
|---|
| 330 |     <input type="hidden" name="lang" value="<%=queryLang%>"> | 
|---|
| 331 |     <input type="hidden" name="hitsPerPage" value="<%=hitsPerPage%>"> | 
|---|
| 332 |     <input type="hidden" name="hitsPerSite" value="0"> | 
|---|
| 333 |     <input type="hidden" name="clustering" value="<%=clustering%>"> | 
|---|
| 334 |     <input type="submit" value="<i18n:message key="showAllHits"/>"> | 
|---|
| 335 | <% if (sort != null) { %> | 
|---|
| 336 |     <input type="hidden" name="sort" value="<%=sort%>"> | 
|---|
| 337 |     <input type="hidden" name="reverse" value="<%=reverse%>"> | 
|---|
| 338 | <% } %> | 
|---|
| 339 |     </form> | 
|---|
| 340 | <% | 
|---|
| 341 |     } | 
|---|
| 342 | %> | 
|---|
| 343 |  | 
|---|
| 344 | <table bgcolor="3333ff" align="right"> | 
|---|
| 345 | <tr><td bgcolor="ff9900"><a href="<%=rss%>"><font color="ffffff"><b>RSS</b> | 
|---|
| 346 | </font></a></td></tr> | 
|---|
| 347 | </table> | 
|---|
| 348 |  | 
|---|
| 349 | <p> | 
|---|
| 350 | <a href="http://wiki.apache.org/nutch/FAQ"> | 
|---|
| 351 | <img border="0" src="../img/poweredbynutch_01.gif"> | 
|---|
| 352 | </a> | 
|---|
| 353 |  | 
|---|
| 354 | <jsp:include page="/include/footer.html"/> | 
|---|
| 355 |  | 
|---|
| 356 | </body> | 
|---|
| 357 | </html> | 
|---|