/// <summary> /// Executes the search using the currently entered text /// </summary> private void LaunchSearch(bool interactive) { if (indexes.Count == 0) { return; } searchStatusLabel.Text = String.Format(Properties.Resources.SearchingForTerm, searchBox.Text); searchLaunched = true; searchIdentifier++; if (!interactive) { SearchItem si = new SearchItem(); si.SearchIdentifier = searchIdentifier; si.SearchText = searchBox.Text; ThreadPool.QueueUserWorkItem(BackgroundSearch, si); return; } HitCollection hits = Indexer.Search(searchBox.Text, indexes.Values, Indexer.MAX_SEARCH_HITS); searchStatusLabel.Text = String.Empty; if (String.IsNullOrEmpty(hits.ErrorMessages)) { loadingResults = true; hitsBox.DataSource = hits; hitsBox.SelectedItem = null; loadingResults = false; if (hits.HadMoreHits) { searchStatusLabel.Text = String.Format(Properties.Resources.ShowingXTopResults, Indexer.MAX_SEARCH_HITS.ToString()); } if (hits.Count > 0) { hitsBox.SetSelected(0, true); PageInfo page = hitsBox.SelectedItem as PageInfo; webBrowser.Navigate(WebServer.Instance.GenerateUrl(page)); } } else { MessageBox.Show(this, hits.ErrorMessages, Properties.Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error); } }
/// <summary> /// Sends the frame page to the client. /// GET request will be sent to request/result.xml?n=5&p=1&s=searchstring where /// n is the maximum number of items per page, the number of <item> allowed in this file /// p is the current page number, if there are multipage pages, page number starts from 1, 2, 3..., /// s is the search query string /// </summary> void ServeRCResultPage() { // Parse parameters NameValueCollection qscoll = Util.ParseHtmlQuery(RequestUri); int numItemsPerPage = Int32.Parse(qscoll.Get("n")); int pageNumber = Int32.Parse(qscoll.Get("p")); string queryString = qscoll.Get("s"); string resultsString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; List<Lucene.Net.Documents.Document> tempLuceneResults = new List<Lucene.Net.Documents.Document>(); List<Lucene.Net.Documents.Document> filteredLuceneResults = new List<Lucene.Net.Documents.Document>(); HitCollection wikiResults = new HitCollection(); int currentItemNumber = 0; if (queryString.Trim().Length > 0) { // Query the Wiki index wikiResults = Indexer.Search(queryString, RCLocalProxy.WikiIndices.Values, Indexer.MAX_SEARCH_HITS); // Query our RuralCafe index List<Lucene.Net.Documents.Document> luceneResults = IndexWrapper.Query(((RCLocalProxy)_proxy).IndexPath, queryString); // remove duplicates foreach (Lucene.Net.Documents.Document document in luceneResults) { string documentUri = document.Get("uri"); string documentTitle = document.Get("title"); // ignore blacklisted domains if (IsBlacklisted(documentUri)) { continue; } bool exists = false; foreach (Lucene.Net.Documents.Document tempDocument in tempLuceneResults) { string documentUri2 = tempDocument.Get("uri"); string documentTitle2 = tempDocument.Get("title"); if (String.Compare (documentUri, documentUri2) == 0 || String.Compare (documentTitle, documentTitle2)==0) { exists = true; break; } } if (exists == false) { currentItemNumber++; tempLuceneResults.Add(document); if ((currentItemNumber > ((pageNumber - 1) * numItemsPerPage)) && (currentItemNumber < (pageNumber * numItemsPerPage) + 1)) { filteredLuceneResults.Add(document); } } } } LogDebug(filteredLuceneResults.Count + " results"); resultsString = resultsString + "<search total=\"" + currentItemNumber + "\">"; //laura: total should be the total number of results // Local Search Results for (int i = 0; i < filteredLuceneResults.Count; i++) { Lucene.Net.Documents.Document result = filteredLuceneResults.ElementAt(i); string uri = System.Security.SecurityElement.Escape(result.Get("uri")); // escape xml string string title = System.Security.SecurityElement.Escape(result.Get("title")); //escape xml string string displayUri = uri; string contentSnippet = ""; // JAY: find content snippet here //contentSnippet = if (uri.StartsWith("http://")) //laura: obmit http:// uri=uri.Substring(7); resultsString = resultsString + "<item>" + "<title>" + title + "</title>" + "<url>" + uri + "</url>" + "<snippet>" + contentSnippet + "</snippet>" + "</item>"; } resultsString = resultsString + "</search>"; SendOkHeaders("text/xml", "Cache-Control: no-cache" + "\r\n" + "Pragma: no-cache" + "\r\n" + "Expires: -1" + "\r\n"); SendMessage(resultsString); }
/// <summary> /// Searches for the specified term in the index. /// </summary> /// <param name="term">The term.</param> public static HitCollection Search(string term, IEnumerable<Indexer> indexers, int maxResults) { foreach (Indexer ixr in indexers) { if (!ixr.indexExists || ixr.searcher == null) { throw new Exception("The index does not exist for " + ixr.filePath); } } string searchRequest = String.Format("title:{0} AND -\"Image:\"", term); HitCollection ret = new HitCollection(); SearchItem si = new SearchItem(); si.Hits = ret; si.SearchRequest = searchRequest; si.MaxResults = maxResults; // I can't really be sure about the thread safety of Lucene lock (typeof(Indexer)) { foreach (Indexer ixr in indexers) { int i = 0; while (ixr.searchRunning && i < 30) { Thread.Sleep(100); i++; } if (i >= 30) { throw new Exception("Failed starting the search work item due to timeout"); } ixr.searchRunning = true; } foreach (Indexer ixr in indexers) { ThreadPool.QueueUserWorkItem(ixr.Search, si); } foreach (Indexer ixr in indexers) { int i = 0; while (ixr.searchRunning && i < 100) { Thread.Sleep(100); i++; } if (i >= 30) { throw new Exception("Failed finishing the search work item due to timeout"); } } } return ret; }
/// <summary> /// Gets called whenever the browser control requests a URL from the web server /// </summary> /// <param name="sender">Web server instance</param> /// <param name="e">Request parameters</param> private void Web_UrlRequested(object sender, UrlRequestedEventArgs e) { string response = "Not found"; string redirect = String.Empty; if (!String.IsNullOrEmpty(e.TeXEquation)) { return; } string topic = e.TopicName.Replace('_', ' ').Trim(); if (topic.Contains("#")) { topic = topic.Substring(0, topic.IndexOf('#')).Trim(); } PageInfo page = hitsBox.SelectedItem as PageInfo; if (page != null && topic.Equals(page.Name, StringComparison.InvariantCultureIgnoreCase) && e.IndexName.Equals(page.Indexer.File, StringComparison.InvariantCultureIgnoreCase) && !IsCircularRedirect(page)) { response = page.GetFormattedContent(); redirect = page.RedirectToTopic; } else { List <Indexer> searchArea = new List <Indexer>(); // This is an internal link if (String.IsNullOrEmpty(e.IndexName)) { if (page != null) { searchArea.Add(page.Indexer); } else { foreach (Indexer ixr in indexes.Values) { searchArea.Add(ixr); } } } else { foreach (Indexer ixr in indexes.Values) { if (ixr.File.Equals(e.IndexName, StringComparison.InvariantCultureIgnoreCase)) { searchArea.Add(ixr); break; } } } if (searchArea.Count > 0) { HitCollection hits = Indexer.Search(topic, searchArea, 100); bool exactTopicLocated = false; foreach (PageInfo pi in hits) { if (pi.Name.Trim().Equals(topic, StringComparison.InvariantCultureIgnoreCase) && !IsCircularRedirect(pi)) { response = pi.GetFormattedContent(); redirect = pi.RedirectToTopic; exactTopicLocated = true; break; } } if (hits.Count > 0 && !exactTopicLocated) { foreach (PageInfo pi in hits) { if (String.IsNullOrEmpty(pi.RedirectToTopic)) { response = pi.GetFormattedContent(); redirect = pi.RedirectToTopic; exactTopicLocated = true; break; } } if (!exactTopicLocated) { foreach (PageInfo pi in hits) { if (!IsCircularRedirect(pi)) { response = pi.GetFormattedContent(); redirect = pi.RedirectToTopic; break; } } } } } } e.Redirect = !String.IsNullOrEmpty(redirect); e.RedirectTarget = redirect; e.Response = Encoding.UTF8.GetBytes(response); e.MimeType = "text/html"; if (String.IsNullOrEmpty(redirect)) { autoRedirects.Clear(); } else { autoRedirects.Push(redirect); } }
/// <summary> /// Searches for the specified term in the index. /// </summary> /// <param name="term">The term.</param> public static HitCollection Search(string queryString, IEnumerable <Indexer> indexers, int maxResults) { foreach (Indexer ixr in indexers) { if (!ixr.indexExists || ixr.searcher == null) { throw new Exception(String.Format(Properties.Resources.IndexDoesNotExist, ixr.filePath)); } } HitCollection ret = new HitCollection(); SearchItem si = new SearchItem(); si.Hits = ret; si.SearchRequest = queryString; si.MaxResults = maxResults; si.Errors = new Queue <Exception>(); int indexersNumber = 0; // I can't really be sure about the thread safety of Lucene try { lock (typeof(Indexer)) { foreach (Indexer ixr in indexers) { indexersNumber++; int i = 0; while (ixr.searchRunning && i < 30) { Thread.Sleep(100); i++; } if (i >= 30) { throw new Exception(Properties.Resources.FailedStartingSearch); } ixr.searchRunning = true; } foreach (Indexer ixr in indexers) { ThreadPool.QueueUserWorkItem(ixr.Search, si); } foreach (Indexer ixr in indexers) { int i = 0; while (ixr.searchRunning && i < 30) { Thread.Sleep(100); i++; } if (i >= 30) { throw new Exception(Properties.Resources.FailedFinishingSearch); } } } } catch (Exception ex) { lock (si.Errors) { si.Errors.Enqueue(ex); } } StringCollection sc = new StringCollection(); lock (si.Errors) { while (si.Errors.Count > 0) { Exception ex = si.Errors.Dequeue(); if (!sc.Contains(ex.Message)) { sc.Add(ex.Message); } } } StringBuilder sb = new StringBuilder(); foreach (string message in sc) { sb.AppendLine(message); } ret.ErrorMessages = sb.Length > 0 ? sb.ToString() : String.Empty; if (indexersNumber > 1) { PageInfo[] arr = new PageInfo[ret.Count]; for (int i = 0; i < ret.Count; i++) { arr[i] = ret[i]; } Array.Sort <PageInfo>(arr, delegate(PageInfo a, PageInfo b) { return(a.Score < b.Score ? 1 : (a.Score > b.Score ? -1 : 0)); }); ret.Clear(); foreach (PageInfo pi in arr) { ret.Add(pi); } } return(ret); }
/// <summary> /// Searches for the specified term in the index. /// </summary> /// <param name="term">The term.</param> public static HitCollection Search(string queryString, IEnumerable<Indexer> indexers, int maxResults) { foreach (Indexer ixr in indexers) { if (!ixr.indexExists || ixr.searcher == null) { throw new Exception(String.Format(Properties.Resources.IndexDoesNotExist, ixr.filePath)); } } HitCollection ret = new HitCollection(); SearchItem si = new SearchItem(); si.Hits = ret; si.SearchRequest = queryString; si.MaxResults = maxResults; si.Errors = new Queue<Exception>(); int indexersNumber = 0; // I can't really be sure about the thread safety of Lucene try { lock (typeof(Indexer)) { foreach (Indexer ixr in indexers) { indexersNumber++; int i = 0; while (ixr.searchRunning && i < 30) { Thread.Sleep(100); i++; } if (i >= 30) { throw new Exception(Properties.Resources.FailedStartingSearch); } ixr.searchRunning = true; } foreach (Indexer ixr in indexers) { ThreadPool.QueueUserWorkItem(ixr.Search, si); } foreach (Indexer ixr in indexers) { int i = 0; while (ixr.searchRunning && i < 30) { Thread.Sleep(100); i++; } if (i >= 30) { throw new Exception(Properties.Resources.FailedFinishingSearch); } } } } catch (Exception ex) { lock (si.Errors) { si.Errors.Enqueue(ex); } } StringCollection sc = new StringCollection(); lock (si.Errors) { while (si.Errors.Count > 0) { Exception ex = si.Errors.Dequeue(); if (!sc.Contains(ex.Message)) { sc.Add(ex.Message); } } } StringBuilder sb = new StringBuilder(); foreach (string message in sc) { sb.AppendLine(message); } ret.ErrorMessages = sb.Length > 0 ? sb.ToString() : String.Empty; if (indexersNumber > 1) { PageInfo[] arr = new PageInfo[ret.Count]; for (int i = 0; i < ret.Count; i++) { arr[i] = ret[i]; } Array.Sort<PageInfo>(arr, delegate(PageInfo a, PageInfo b) { return (a.Score < b.Score ? 1 : (a.Score > b.Score ? -1 : 0)); }); ret.Clear(); foreach (PageInfo pi in arr) { ret.Add(pi); } } return ret; }