/// <summary> /// Constructor /// </summary> /// <param name="index"></param> /// <param name="settings"></param> /// <param name="language"></param> public VulcanClient(string index, ConnectionSettings settings, CultureInfo language) : base(settings) { if (language == null) { throw new Exception("Vulcan client requires a language (you may use CultureInfo.InvariantCulture if needed for non-language specific data)"); } Language = language; IndexName = VulcanHelper.GetIndexName(index, Language); }
/// <summary> /// Get a Vulcan client /// </summary> /// <param name="language">Pass in null for current culture, a specific culture or CultureInfo.InvariantCulture to get a client for non-language specific data</param> /// <returns>A Vulcan client</returns> public virtual IVulcanClient GetClient(CultureInfo language = null) { var cultureInfo = language ?? CultureInfo.CurrentUICulture; IVulcanClient storedClient; if (clients.TryGetValue(cultureInfo, out storedClient)) { return(storedClient); } lock (lockObject) { // we now know what our culture is (current culture or invariant), but we need to choose the language analyzer var languageAnalyzer = VulcanHelper.GetAnalyzer(cultureInfo); var indexName = VulcanHelper.GetIndexName(Index, cultureInfo); var settings = CommonConnectionSettings.Service.ConnectionSettings; settings.InferMappingFor <ContentMixin>(pd => pd.Ignore(p => p.MixinInstance)); settings.DefaultIndex(indexName); var client = CreateVulcanClient(Index, settings, cultureInfo); // first let's check our version var nodesInfo = client.NodesInfo(); if (nodesInfo?.Nodes?.Any() != true) { throw new Exception("Could not get Nodes info to check Elasticsearch Version. Check that you are correctly connected to Elasticsearch?"); } else { var node = nodesInfo.Nodes.First(); // just use first if (string.IsNullOrWhiteSpace(node.Value.Version)) // just use first { throw new Exception("Could not find a version on node to check Elasticsearch Version. Check that you are correctly connected to Elasticsearch?"); } else { if (node.Value.Version.StartsWith("1.")) { throw new Exception("Sorry, Vulcan only works with Elasticsearch version 2.x or higher. The Elasticsearch node you are currently connected to is version " + node.Value.Version); } } } client.RunCustomIndexTemplates(Index, Logger); // keep our base last with lowest possible Order client.PutIndexTemplate($"{Index}_analyzer_disabling", ad => ad .Order(0) .Template($"{Index}*") //match on all created indices for index name .Mappings(mappings => mappings.Map("_default_", map => map.DynamicTemplates( dyn => dyn.DynamicTemplate("analyzer_template", dt => dt .Match("*") //matches all fields .MatchMappingType("string") //that are a string .Mapping(dynmap => dynmap.String(s => s .NotAnalyzed() .IgnoreAbove(CreateIndexCustomizer.Service.IgnoreAbove) // needed for: document contains at least one immense term in field .IncludeInAll(false) .Fields(f => f .String(ana => ana .Name(VulcanFieldConstants.AnalyzedModifier) .IncludeInAll(false) .Store(true) ) )) ) ))))); if (!client.IndexExists(indexName).Exists) { var response = client.CreateIndex(indexName, CreateIndexCustomizer.Service.CustomizeIndex); if (!response.IsValid) { Logger.Error("Could not create index " + indexName + ": " + response.DebugInformation); } } client.Refresh(indexName); var closeResponse = client.CloseIndex(indexName); if (!closeResponse.IsValid) { Logger.Error("Could not close index " + indexName + ": " + closeResponse.DebugInformation); } InitializeAnalyzer(client); client.RunCustomizers(Logger); // allows for customizations var openResponse = client.OpenIndex(indexName); var initShards = client.ClusterHealth(x => x.WaitForActiveShards(CreateIndexCustomizer.Service.WaitForActiveShards)); // fixes empty results on first request clients.Add(cultureInfo, client); return(client); } }
/// <summary> /// Search for content /// </summary> /// <typeparam name="T"></typeparam> /// <param name="searchDescriptor"></param> /// <param name="includeNeutralLanguage"></param> /// <param name="rootReferences"></param> /// <param name="typeFilter"></param> /// <param name="principleReadFilter"></param> /// <returns></returns> public virtual ISearchResponse <IContent> SearchContent <T>( Func <SearchDescriptor <T>, SearchDescriptor <T> > searchDescriptor = null, bool includeNeutralLanguage = false, IEnumerable <ContentReference> rootReferences = null, IEnumerable <Type> typeFilter = null, IPrincipal principleReadFilter = null) where T : class, IContent { SearchDescriptor <T> resolvedDescriptor; if (searchDescriptor == null) { resolvedDescriptor = new SearchDescriptor <T>(); } else { resolvedDescriptor = searchDescriptor.Invoke(new SearchDescriptor <T>()); } typeFilter = typeFilter ?? typeof(T).GetSearchTypesFor(VulcanFieldConstants.AbstractFilter); resolvedDescriptor = resolvedDescriptor.Type(string.Join(",", typeFilter.Select(t => t.FullName))) .ConcreteTypeSelector((d, docType) => typeof(VulcanContentHit)); var indexName = IndexName; if (Language != CultureInfo.InvariantCulture && includeNeutralLanguage) { indexName += "," + VulcanHelper.GetIndexName(VulcanHandler.Service.Index, CultureInfo.InvariantCulture); } resolvedDescriptor = resolvedDescriptor.Index(indexName); var validRootReferences = rootReferences?.Where(x => !ContentReference.IsNullOrEmpty(x)).ToList(); List <QueryContainer> filters = new List <QueryContainer>(); if (validRootReferences?.Count > 0) { var scopeDescriptor = new QueryContainerDescriptor <T>(). Terms(t => t.Field(VulcanFieldConstants.Ancestors).Terms(validRootReferences.Select(x => x.ToReferenceWithoutVersion().ToString()))); filters.Add(scopeDescriptor); } if (principleReadFilter != null) { var permissionDescriptor = new QueryContainerDescriptor <T>(). Terms(t => t.Field(VulcanFieldConstants.ReadPermission).Terms(principleReadFilter.GetRoles())); filters.Add(permissionDescriptor); } if (filters.Count > 0) { Func <SearchDescriptor <T>, ISearchRequest> selector = ts => resolvedDescriptor; var container = selector.Invoke(new SearchDescriptor <T>()); if (container.Query != null) { filters.Insert(0, container.Query); } resolvedDescriptor = resolvedDescriptor.Query(q => q.Bool(b => b.Must(filters.ToArray()))); } var response = base.Search <T, IContent>(resolvedDescriptor); return(response); }