/// <summary> /// Gets a list of query suggestions for providing typeahead support. /// </summary> public override async Task <GetQuerySuggestionsResponse> GetQuerySuggestions(GetQuerySuggestionsRequest request, ServerCallContext context) { string firstLetter = request.Query.Substring(0, 1); PreparedStatement preparedStatement = await _statementCache.GetOrAddAsync("SELECT tag FROM tags_by_letter WHERE first_letter = ? AND tag >= ? LIMIT ?"); BoundStatement boundStatement = preparedStatement.Bind(firstLetter, request.Query, request.PageSize); RowSet rows = await _session.ExecuteAsync(boundStatement).ConfigureAwait(false); var response = new GetQuerySuggestionsResponse { Query = request.Query }; response.Suggestions.Add(rows.Select(row => row.GetValue <string>("tag"))); return(response); }
/// <summary> /// Gets a list of query suggestions for providing typeahead support. /// </summary> public override async Task <GetQuerySuggestionsResponse> GetQuerySuggestions(GetQuerySuggestionsRequest request, ServerCallContext context) { // Get REST client for dse-search service Uri searchUri = await GetDseSearchUri().ConfigureAwait(false); IRestClient restClient = _createRestClient(searchUri); var restRequest = new RestRequest("killrvideo.videos/suggest") { Method = Method.POST }; restRequest.AddParameter("wt", "json"); // We'll build on every query, but in a real production app, we'd probably only do this occasionally or use the Solr config to setup // build on commit/optimize of the index restRequest.AddParameter("suggest.build", "true"); restRequest.AddParameter("suggest.q", request.Query); IRestResponse <SearchResult> restResponse = await restClient.ExecuteTaskAsync <SearchResult>(restRequest).ConfigureAwait(false); // Start with an empty response (i.e. no suggestions) var response = new GetQuerySuggestionsResponse { Query = request.Query }; // Check for network/timeout errors if (restResponse.ResponseStatus != ResponseStatus.Completed) { // TODO: Logger.Error(response.ErrorException, "Error while querying Solr search suggestions from {host} for {query}", nodeIp, getSuggestions.Query); return(response); } // Check for HTTP error codes if (restResponse.StatusCode != HttpStatusCode.OK) { // TODO: Logger.Error("HTTP status code {code} while querying Solr video suggestions from {host} for {query}", (int)response.StatusCode, nodeIp, getSuggestions.Query); return(response); } // Success, add responses from DSE Search to gRPC response response.Suggestions.Add( restResponse.Data.Suggest.SearchSuggester[request.Query].Suggestions.Select(s => s.Term) ); return(response); }
/// <summary> /// Gets a list of query suggestions for providing typeahead support. /// </summary> public override async Task <GetQuerySuggestionsResponse> GetQuerySuggestions(GetQuerySuggestionsRequest request, ServerCallContext context) { // Set the base URL of the REST client to use the first node in the Cassandra cluster string nodeIp = _session.Cluster.AllHosts().First().Address.Address.ToString(); _restClient.BaseUrl = new Uri($"http://{nodeIp}:8983/solr"); var restRequest = new RestRequest("killrvideo.videos/suggest") { Method = Method.POST }; restRequest.AddParameter("wt", "json"); // Requires a build after new names are added, added on a safe side. restRequest.AddParameter("spellcheck.build", "true"); restRequest.AddParameter("spellcheck.q", request.Query); IRestResponse <SearchSuggestionResult> restResponse = await _restClient.ExecuteTaskAsync <SearchSuggestionResult>(restRequest).ConfigureAwait(false); // Start with an empty response (i.e. no suggestions) var response = new GetQuerySuggestionsResponse { Query = request.Query }; // Check for network/timeout errors if (restResponse.ResponseStatus != ResponseStatus.Completed) { // TODO: Logger.Error(response.ErrorException, "Error while querying Solr search suggestions from {host} for {query}", nodeIp, getSuggestions.Query); return(response); } // Check for HTTP error codes if (restResponse.StatusCode != HttpStatusCode.OK) { // TODO: Logger.Error("HTTP status code {code} while querying Solr video suggestions from {host} for {query}", (int)response.StatusCode, nodeIp, getSuggestions.Query); return(response); } // Success /* * The spellcheck.suggestions object that comes back in the JSON looks something like this (for example, searching for 'cat'): * * "suggestions": [ * "cat", * { * "numFound": 1, * "startOffset": 0, * "endOffset": 3, * "suggestion": [ * "cat summer video teaser" * ] * } * ] * * Yes, that's an array of mixed objects (seriously, WTF kind of an API is that Solr?!). Since the array is mixed, we deserialized * it as a List<string> where the second element will be the JSON string with the actual data we care about. We need to now run * deserialization again on that to get at the actual data. */ if (restResponse.Data.Spellcheck.Suggestions.Count >= 2) { // Deserialize the embedded object var suggestions = JsonConvert.DeserializeObject <SearchSpellcheckSuggestions>(restResponse.Data.Spellcheck.Suggestions.Last()); // Add to response if the object deserialized correctly if (suggestions.Suggestion != null) { response.Suggestions.Add(suggestions.Suggestion); } } return(response); }