private IEnumerable <LocationItemPage> GetRelatedLocations(LocationItemPage currentPage) { IQueriedSearch <LocationItemPage> query = SearchClient.Instance .Search <LocationItemPage>() .MoreLike(SearchTextFly(currentPage)) .BoostMatching(x => x.Country.Match(currentPage.Country ?? ""), 2) .BoostMatching(x => x.Continent.Match(currentPage.Continent ?? ""), 1.5) .BoostMatching(x => x.Coordinates .WithinDistanceFrom(currentPage.Coordinates ?? new GeoLocation(0, 0), 1000.Kilometers()), 2.5); query = currentPage.Category.Aggregate(query, (current, category) => current.BoostMatching(x => x.InCategory(category), 1.5)); return(query .Filter(x => !x.PageLink.Match(currentPage.PageLink)) .PublishedInCurrentLanguage() .FilterForVisitor() .Take(3) .GetPagesResult()); }
/// <summary> /// Adds content type boosts to the search. /// </summary> /// <typeparam name="T">The type to query for.</typeparam> /// <param name="query">The query.</param> /// <param name="favoriteUserContent">The content types to boost, with the boost factor.</param> /// <returns>The <see cref="IQueriedSearch{T}"/> with added BoostMatching.</returns> /// <remarks><para>The BoostMatching method must be called before any method not related to the search query (such as Filter, Take, and Skip).</para> /// <para>This is enforced by the fact that the For method in the above sample returns a IQueriedSearch object.</para> /// </remarks> public static IQueriedSearch <T> AddContentTypeBoosts <T>( this IQueriedSearch <T> query, Dictionary <int, int> favoriteUserContent) where T : IContent { return(favoriteUserContent.Aggregate( query, (current, favoriteContent) => current.BoostMatching(x => x.ContentTypeID.Match(favoriteContent.Key), favoriteContent.Value))); }
/// <summary> /// Adds category boosts to the search. /// </summary> /// <typeparam name="T">The type to query for.</typeparam> /// <param name="query">The query.</param> /// <param name="favoriteCategories">The categories to boost, with the boost factor.</param> /// <returns>The <see cref="IQueriedSearch{T}"/> with added BoostMatching.</returns> /// <remarks><para>The BoostMatching method must be called before any method not related to the search query (such as Filter, Take, and Skip).</para> /// <para>This is enforced by the fact that the For method in the above sample returns a IQueriedSearch object.</para> /// </remarks> public static IQueriedSearch <T> AddCategoryBoosts <T>( this IQueriedSearch <T> query, Dictionary <int, int> favoriteCategories) where T : ICategorizable { return(favoriteCategories.Aggregate( query, (current, favoriteCategory) => current.BoostMatching(x => x.Category.In(new[] { favoriteCategory.Key }), favoriteCategory.Value))); }
static void SearchEverythingFor(string q) { WriteLine($"* Search for everything with: {q}"); ITypeSearch <object> search = client.Search <object>(); // perform a "free text" query IQueriedSearch <object> query = search.For(q); OutputResults(query as ITypeSearch <object>); }
static void SearchBooksFor(string q) { WriteLine($"* Search for books with: {q}"); // only look for "books" and allow word stemming ITypeSearch <Book> search = client.Search <Book>(Language.English); // perform a "free text" query looking in Title and Description IQueriedSearch <Book> query = search.For(q) .InField(x => x.Title, 3.0) // triple the weighting for matches in Title .InField(x => x.Description); OutputResults(query as ITypeSearch <Book>); }
public static bool TryGetQueryStringQuery <TSource>(IQuery query, IQueriedSearch <TSource> search, out MultiFieldQueryStringQuery currentQueryStringQuery) { currentQueryStringQuery = query as MultiFieldQueryStringQuery; if (currentQueryStringQuery == null) { // Synonyms are only supported for QueryStringQuery Find.Tracing.Trace.Instance.Add(new TraceEvent(search, "The use of synonyms are only supported för QueryStringQueries, i.e. with the use of the .For() -extensions. The query will be executed without the use of synonyms.") { IsError = false }); return(false); } return(true); }
/// <summary> /// Searches for the specified query in all default search fields, and in the specified locale. /// </summary> /// <param name="search">The search to modify.</param> /// <param name="query">The query text to search for.</param> /// <param name="locale">The locale to search in.</param> /// <returns>The search, modified to include the requested query.</returns> public static ITypeSearch <FindDocument> ForDefaultFields(this ITypeSearch <FindDocument> search, string query, string locale) { if (!string.IsNullOrEmpty(query)) { ISearchConfiguration configuration = search.Client.GetConfiguration(); IQueriedSearch <FindDocument, QueryStringQuery> search1 = search.For <FindDocument>(query); Enumerable.Empty <IFieldConfiguration>(); foreach (IFieldConfiguration fieldConfiguration1 in !string.IsNullOrWhiteSpace(locale) ? configuration.GetDefaultFields(locale) : configuration.GetDefaultFields()) { if (fieldConfiguration1.Type == typeof(string)) { IFieldConfiguration <string> fieldConfiguration2 = (IFieldConfiguration <string>)fieldConfiguration1; search1 = search1.InField <FindDocument, QueryStringQuery>(fieldConfiguration2.TypedGetValueExpression, new double?()); } else if (fieldConfiguration1.Type == typeof(IEnumerable <string>)) { IFieldConfiguration <IEnumerable <string> > fieldConfiguration2 = (IFieldConfiguration <IEnumerable <string> >)fieldConfiguration1; search1 = search1.InField <FindDocument, QueryStringQuery>(fieldConfiguration2.TypedGetValueExpression, new double?()); } else if (fieldConfiguration1.Type == typeof(int?)) { IFieldConfiguration <int?> fieldConfiguration2 = (IFieldConfiguration <int?>)fieldConfiguration1; search1 = search1.InField <FindDocument, QueryStringQuery>(fieldConfiguration2.TypedGetValueExpression, new double?()); } else if (fieldConfiguration1.Type == typeof(int)) { IFieldConfiguration <int> fieldConfiguration2 = (IFieldConfiguration <int>)fieldConfiguration1; search1 = search1.InField <FindDocument, QueryStringQuery>(fieldConfiguration2.TypedGetValueExpression, new double?()); } else if (fieldConfiguration1.Type == typeof(double?) || fieldConfiguration1.Type == typeof(float?)) { IFieldConfiguration <double?> fieldConfiguration2 = (IFieldConfiguration <double?>)fieldConfiguration1; search1 = search1.InField <FindDocument, QueryStringQuery>(fieldConfiguration2.TypedGetValueExpression, new double?()); } else { if (!(fieldConfiguration1.Type == typeof(double)) && !(fieldConfiguration1.Type == typeof(float))) { throw new Exception(string.Format((IFormatProvider)CultureInfo.InvariantCulture, "Field of type {0} is not valid for the default search.", (object)fieldConfiguration1.Type.Name)); } IFieldConfiguration <double> fieldConfiguration2 = (IFieldConfiguration <double>)fieldConfiguration1; search1 = search1.InField <FindDocument, QueryStringQuery>(fieldConfiguration2.TypedGetValueExpression, new double?()); } } search = (ITypeSearch <FindDocument>)search1; } return(search); }
public static IQueriedSearch <TSource, QueryStringQuery> UsingRelevanceImproved <TSource>(this IQueriedSearch <TSource> search, params Expression <Func <TSource, string> >[] fieldSelectors) { return(new Search <TSource, QueryStringQuery>(search, context => { BoolQuery currentBoolQuery; BoolQuery newBoolQuery = new BoolQuery(); MinShouldMatchQueryStringQuery currentQueryStringQuery; if (QueryHelpers.TryGetBoolQuery(context.RequestBody.Query, out currentBoolQuery)) { if (!QueryHelpers.TryGetMinShouldMatchQueryStringQuery(currentBoolQuery.Should[0], out currentQueryStringQuery)) { return; } newBoolQuery = currentBoolQuery; } else { currentBoolQuery = new BoolQuery(); if (!QueryHelpers.TryGetMinShouldMatchQueryStringQuery(context.RequestBody.Query, out currentQueryStringQuery)) { return; } newBoolQuery.Should.Add(currentQueryStringQuery); } // If .UsingImprovedSynonyms has not been used there is no ExpandedQuery for us then we use the query if (currentQueryStringQuery.ExpandedQuery.IsNull()) { currentQueryStringQuery.ExpandedQuery = new string[] { currentQueryStringQuery.Query.ToString().Replace("¤", " ") }; } foreach (var query in currentQueryStringQuery.ExpandedQuery) { var terms = QueryHelpers.GetQueryPhrases(query); foreach (var fieldSelector in fieldSelectors) { var fieldNameLowercase = search.Client.Conventions.FieldNameConvention.GetFieldNameForLowercase(fieldSelector); var fieldNameAnalyzed = search.Client.Conventions.FieldNameConvention.GetFieldNameForAnalyzed(fieldSelector); // Create PrefixQuery for single term queries larger than 2 characters if (terms.Count() == 1 && terms.First().Length > 2) { var prefixQuery = new PrefixQuery(fieldNameLowercase, query.ToLower()) { Boost = 0.5 }; newBoolQuery.Should.Add(prefixQuery); } // Create PhraseQuery and PhrasePrefixQuery for multiple term queries if (terms.Count() > 1) { var phraseQuery = new PhraseQuery(fieldNameAnalyzed, query) { Boost = 5 }; var phrasePrefixQuery = new PhrasePrefixQuery(fieldNameLowercase, query.ToLower()) { Boost = 10 }; newBoolQuery.Should.Add(phraseQuery); newBoolQuery.Should.Add(phrasePrefixQuery); } } } if (newBoolQuery.Should.Count == 0) { return; } context.RequestBody.Query = newBoolQuery; })); }
public static IQueriedSearch <TSource, MinShouldMatchQueryStringQuery> MinimumShouldMatch <TSource>(this IQueriedSearch <TSource> search, string minMatch) { return(new Search <TSource, MinShouldMatchQueryStringQuery>(search, context => { var originalQuery = (QueryStringQuery)context.RequestBody.Query; var query = new MinShouldMatchQueryStringQuery(originalQuery.Query); query.RawQuery = originalQuery.RawQuery; query.AllowLeadingWildcard = originalQuery.AllowLeadingWildcard; query.AnalyzeWildcard = originalQuery.AnalyzeWildcard; query.Analyzer = originalQuery.Analyzer; query.AutoGeneratePhraseQueries = originalQuery.AutoGeneratePhraseQueries; query.Boost = originalQuery.Boost; query.DefaultOperator = originalQuery.DefaultOperator; query.EnablePositionIncrements = originalQuery.EnablePositionIncrements; query.FuzzyMinSim = originalQuery.FuzzyMinSim; query.FuzzyPrefixLength = originalQuery.FuzzyPrefixLength; query.LowercaseExpandedTerms = originalQuery.LowercaseExpandedTerms; query.PhraseSlop = originalQuery.PhraseSlop; query.DefaultField = originalQuery.DefaultField; var multiFieldQuery = context.RequestBody.Query as MultiFieldQueryStringQuery; if (multiFieldQuery != null) { query.Fields = multiFieldQuery.Fields; } query.MinimumShouldMatch = minMatch; context.RequestBody.Query = query; })); }
public static IQueriedSearch <TSource, QueryStringQuery> UsingSynonymsImproved <TSource>(this IQueriedSearch <TSource> search, UsingSynonymService usingSynonymService, TimeSpan?cacheDuration = null) { return(usingSynonymService.UsingSynonyms(search, cacheDuration)); }
public static IQueriedSearch <TSource, QueryStringQuery> WildcardMatch <TSource>(this IQueriedSearch <TSource> search, params Expression <Func <TSource, string> >[] fieldSelectors) { return(new Search <TSource, QueryStringQuery>(search, context => { BoolQuery currentBoolQuery; BoolQuery newBoolQuery = new BoolQuery(); MinShouldMatchQueryStringQuery currentQueryStringQuery; if (QueryHelpers.TryGetBoolQuery(context.RequestBody.Query, out currentBoolQuery)) { if (!QueryHelpers.TryGetMinShouldMatchQueryStringQuery(currentBoolQuery.Should[0], out currentQueryStringQuery)) { return; } newBoolQuery = currentBoolQuery; } else { if (!QueryHelpers.TryGetMinShouldMatchQueryStringQuery(context.RequestBody.Query, out currentQueryStringQuery)) { return; } newBoolQuery.Should.Add(currentQueryStringQuery); } var query = QueryHelpers.GetRawQueryString(currentQueryStringQuery); if (query.IsNullOrEmpty()) { return; } // Do not trigger on synonym expansions which are parenthesized and not on quoted searches. if (IsParenthesized(query) || QueryHelpers.IsStringQuoted(query)) { return; } var terms = QueryHelpers.GetQueryPhrases(query); // Only take terms > 2 chars and take max 3 of these string[] candidateTerms = terms.Where(x => x.Length > 2).Take(3).Select(x => string.Format("{0}{1}", x, "*")).ToArray(); if (candidateTerms.Count() == 0) { return; } List <string> fieldNames = new List <string>(); foreach (var fieldSelector in fieldSelectors) { string fieldName = search.Client.Conventions .FieldNameConvention .GetFieldNameForAnalyzed(fieldSelector); fieldNames.Add(fieldName); } var wildcardQueryString = string.Join(" ", candidateTerms); var wildcardQuery = new MinShouldMatchQueryStringQuery(wildcardQueryString) { Fields = fieldNames, DefaultOperator = currentQueryStringQuery.DefaultOperator, MinimumShouldMatch = currentQueryStringQuery.MinimumShouldMatch, Boost = 0.2 }; newBoolQuery.Should.Add(wildcardQuery); context.RequestBody.Query = newBoolQuery; })); }
public static IQueriedSearch <TSource, QueryStringQuery> UsingSynonymsImproved <TSource>(this IQueriedSearch <TSource> search, TimeSpan?cacheDuration = null) { return(UsingSynonymsImproved(search, _lazyUsingSynonymService.Value, cacheDuration)); }
public IQueriedSearch <TSource, QueryStringQuery> UsingSynonyms <TSource>(IQueriedSearch <TSource> search, TimeSpan?cacheDuration = null) { if (search.Client.Settings.Admin) { return(new Search <TSource, QueryStringQuery>(search, context => { if (context.RequestBody.Query != null) { BoolQuery newBoolQuery = new BoolQuery(); BoolQuery currentBoolQuery; MultiFieldQueryStringQuery currentQueryStringQuery; if (QueryHelpers.TryGetBoolQuery(context.RequestBody.Query, out currentBoolQuery)) { if (!QueryHelpers.TryGetQueryStringQuery(currentBoolQuery.Should[0], search, out currentQueryStringQuery)) { return; } } else { if (!QueryHelpers.TryGetQueryStringQuery(context.RequestBody.Query, search, out currentQueryStringQuery)) { return; } } var query = QueryHelpers.GetQueryString(currentQueryStringQuery); if (query.IsNullOrEmpty()) { return; } // If MinimumShouldMatch has been set previously pick up the minShouldMatch value MinShouldMatchQueryStringQuery currentMinShouldMatchQueryStringQuery; string minShouldMatch = ""; if (QueryHelpers.TryGetMinShouldMatchQueryStringQuery(currentQueryStringQuery, out currentMinShouldMatchQueryStringQuery)) { minShouldMatch = currentMinShouldMatchQueryStringQuery.MinimumShouldMatch; } var synonymDictionary = _synonymLoader.GetSynonyms(cacheDuration); var queryPhrases = QueryHelpers.GetQueryPhrases(query).ToArray(); if (queryPhrases.Count() == 0) { return; } HashSet <string> queriesForMatch; string queryNotExpanded = string.Join(" ", queryPhrases); string queryExpanded; if (!GetQueryExpanded(queryPhrases, synonymDictionary, out queryExpanded, out queriesForMatch)) { return; } // Add non expanded query. Using the custom MinimumShouldMatch if set. if (queryNotExpanded.IsNotNullOrEmpty()) { var minShouldMatchQuery = CreateQuery(queryNotExpanded, currentQueryStringQuery, ""); // MinimumShouldMatch() overrides WithAndAsDefaultOperator() if (minShouldMatch.IsNotNullOrEmpty()) { minShouldMatchQuery.MinimumShouldMatch = minShouldMatch; } // Emulate WithAndAsDefaultOperator() using MinimumShouldMatch set to 100% else if (currentQueryStringQuery.DefaultOperator == BooleanOperator.And) { minShouldMatchQuery.MinimumShouldMatch = "100%"; } // We save all variations of queries with and without synonym expansions // to be picked up by UsingImprovedRelevance() // Only allow for 3 queriesForMatch minShouldMatchQuery.ExpandedQuery = queriesForMatch.Take(3).ToArray(); newBoolQuery.Should.Add(minShouldMatchQuery); } // Add expanded query. MinimumShouldMatch is always 1 here. if (queryExpanded.IsNotNullOrEmpty()) { var minShouldMatchQuery = CreateQuery(queryExpanded, currentQueryStringQuery, "1"); newBoolQuery.Should.Add(minShouldMatchQuery); } if (newBoolQuery.IsNull()) { return; } // Keep all QueryStringQuery except the first Should generated by For() if (currentBoolQuery.IsNotNull()) { foreach (var currentQuery in currentBoolQuery.Should.Skip(1)) { newBoolQuery.Should.Add(currentQuery); } foreach (var currentQuery in currentBoolQuery.Must) { newBoolQuery.Must.Add(currentQuery); } foreach (var currentQuery in currentBoolQuery.MustNot) { newBoolQuery.MustNot.Add(currentQuery); } } context.RequestBody.Query = newBoolQuery; } })); } else { Find.Tracing.Trace.Instance.Add(new TraceEvent(search, "Your index does not support synonyms. Please contact support to have your account upgraded. Falling back to search without synonyms.") { IsError = false }); return(new Search <TSource, QueryStringQuery>(search, context => { })); } }