/// <summary> /// Gets all vulcan clients /// </summary> /// <returns></returns> public virtual IVulcanClient[] GetClients(string alias = null) { VulcanHelper.GuardForNullAlias(ref alias); var clientList = new List <IVulcanClient>(); var client = CreateElasticClient(CommonConnectionSettings.ConnectionSettings); var aliasStart = Index + "-" + alias; var aliases = client.CatAliases()?.Records.Where(a => a.Alias.StartsWith(aliasStart)).ToList(); if (aliases?.Any() != true) { return(clientList.ToArray()); } var indices = aliases.Select(a => a.Index).ToList(); if (indices.Any() != true) { return(clientList.ToArray()); } clientList.AddRange ( indices .Select(index => index.Substring(Index.Length + 16)) .Select(cultureName => GetClient(cultureName.Equals("invariant", StringComparison.OrdinalIgnoreCase) ? CultureInfo.InvariantCulture : new CultureInfo(cultureName) ) ) ); return(clientList.ToArray()); }
/// <summary> /// Swaps alias for culture /// </summary> /// <param name="language"></param> /// <param name="oldAlias"></param> /// <param name="newAlias"></param> public void SwitchAlias(CultureInfo language, string oldAlias, string newAlias) { lock (this) { var cultureInfo = language ?? CultureInfo.CurrentUICulture; VulcanHelper.GuardForNullAlias(ref oldAlias); VulcanHelper.GuardForNullAlias(ref newAlias); var client = CreateElasticClient(CommonConnectionSettings.ConnectionSettings); // use a raw elasticclient because we just need this to be quick var oldFullAlias = VulcanHelper.GetAliasName(Index, cultureInfo, oldAlias); var newFullAlias = VulcanHelper.GetAliasName(Index, cultureInfo, newAlias); var oldIndex = client.GetAlias(a => a.Name(oldFullAlias)).Indices?.First().Key; var newIndex = client.GetAlias(a => a.Name(newFullAlias)).Indices?.First().Key; client.Alias(bad => bad.Remove(a => a.Alias(oldFullAlias).Index("*")) .Remove(a => a.Alias(newFullAlias).Index("*")) .Add(a => a.Alias(oldFullAlias).Index(newIndex)) .Add(a => a.Alias(newFullAlias).Index(oldIndex))); client.Refresh("*"); Clients?.Clear(); // force a client refresh } }
/// <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 { var resolvedDescriptor = searchDescriptor == null ? new SearchDescriptor <T>() : 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.Equals(CultureInfo.InvariantCulture) && includeNeutralLanguage) { indexName += "," + VulcanHelper.GetAliasName(VulcanHandler.Index, CultureInfo.InvariantCulture, IndexAlias); } resolvedDescriptor = resolvedDescriptor.Index(indexName); var validRootReferences = rootReferences?.Where(x => !ContentReference.IsNullOrEmpty(x)).ToList(); var 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) { var descriptor = resolvedDescriptor; Func <SearchDescriptor <T>, ISearchRequest> selector = ts => descriptor; 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 = Search <T, IContent>(resolvedDescriptor); return(response); }
/// <summary> /// Delete content for all clients /// </summary> /// <param name="contentLink"></param> /// <param name="typeName"></param> /// <param name="alias"></param> public virtual void DeleteContentEveryLanguage(ContentReference contentLink, string typeName, string alias = null) { VulcanHelper.GuardForNullAlias(ref alias); // we don't know what language(s), or even if invariant, so send a delete request to all foreach (var client in GetClients(alias)) { client.DeleteContent(contentLink, typeName); } }
/// <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> /// Delete content by language /// </summary> /// <param name="content"></param> /// <param name="alias"></param> public virtual void DeleteContentByLanguage(IContent content, string alias = null) { VulcanHelper.GuardForNullAlias(ref alias); IVulcanClient client; if (content is ILocalizable localizable) { client = GetClient(localizable.Language, alias); } else { client = GetClient(CultureInfo.InvariantCulture, alias); } client.DeleteContent(content); }
/// <summary> /// DI Constructor /// </summary> /// <param name="index"></param> /// <param name="indexAlias"></param> /// <param name="settings"></param> /// <param name="language"></param> /// <param name="contentLoader"></param> /// <param name="vulcanHandler"></param> /// <param name="vulcanPipelineSelector"></param> public VulcanClient ( string index, string indexAlias, IConnectionSettingsValues settings, CultureInfo language, IContentLoader contentLoader, IVulcanHandler vulcanHandler, IVulcanPipelineSelector vulcanPipelineSelector) : base(settings) { Language = language ?? throw new Exception("Vulcan client requires a language (you may use CultureInfo.InvariantCulture if needed for non-language specific data)"); IndexName = VulcanHelper.GetAliasName(index, language, indexAlias); IndexAlias = indexAlias; ContentLoader = contentLoader; VulcanHandler = vulcanHandler; _vulcanPipelineSelector = vulcanPipelineSelector; }
/// <summary> /// Delete item /// </summary> /// <param name="pocoIndexer"></param> /// <param name="item"></param> /// <param name="alias"></param> public virtual void DeleteItem(IVulcanPocoIndexer pocoIndexer, object item, string alias = null) { VulcanHelper.GuardForNullAlias(ref alias); var id = pocoIndexer.GetItemIdentifier(item); var type = GetTypeName(item); try { var invariantClient = GetInvariantClient(alias); var response = invariantClient.Delete(new DeleteRequest(invariantClient.IndexName, type, id)); Logger.Debug("Vulcan deleted " + id + " for type " + type + ": " + response.DebugInformation); } catch (Exception e) { Logger.Warning("Vulcan could not delete object of type " + type + " with ID " + id, e); } }
/// <summary> /// Index item /// </summary> /// <param name="pocoIndexer"></param> /// <param name="item"></param> /// <param name="alias"></param> public virtual void IndexItem(IVulcanPocoIndexer pocoIndexer, object item, string alias = null) { var id = pocoIndexer.GetItemIdentifier(item); var type = GetTypeName(item); VulcanHelper.GuardForNullAlias(ref alias); try { var invariantClient = GetInvariantClient(alias); var response = invariantClient.Index(item, z => z.Id(id).Type(type)); Logger.Debug($"Vulcan indexed {id} for type {type}: {response.DebugInformation}"); } catch (Exception e) { Logger.Warning($"Vulcan could not index object of type {type} with ID {id}", e); } }
/// <summary> /// Index content for all langauges /// </summary> /// <param name="content"></param> /// <param name="alias"></param> public virtual void IndexContentEveryLanguage(IContent content, string alias = null) { VulcanHelper.GuardForNullAlias(ref alias); if (content is ILocalizable localizable) { foreach (var language in localizable.ExistingLanguages) { var client = GetClient(language, alias); client.IndexContent(ContentLoader.Get <IContent>(content.ContentLink.ToReferenceWithoutVersion(), language)); } } else { var client = GetClient(CultureInfo.InvariantCulture, alias); client.IndexContent(content); } }
/// <summary> /// Swap all culture aliases /// </summary> /// <param name="oldAlias"></param> /// <param name="newAlias"></param> public void SwitchAliasAllCultures(string oldAlias, string newAlias) { lock (this) { VulcanHelper.GuardForNullAlias(ref oldAlias); VulcanHelper.GuardForNullAlias(ref newAlias); var aliasOldStart = Index + "-" + oldAlias + "_"; var aliasNewStart = Index + "-" + newAlias + "_"; var client = CreateElasticClient(CommonConnectionSettings.ConnectionSettings); // use a raw elasticclient because we just need this to be quick var aliases = client.CatAliases()?.Records.Where(a => a.Alias.StartsWith(Index + "-")).ToList(); var handled = new List <string>(); if (aliases != null) { foreach (var alias in aliases) { if (handled.Contains(alias.Alias)) { continue; } // haven't handled this yet! string checkAlias = null; if (alias.Alias.StartsWith(aliasOldStart)) { checkAlias = alias.Alias.Replace("-" + oldAlias + "_", "-" + newAlias + "_"); } else if (alias.Alias.StartsWith(aliasNewStart)) { checkAlias = alias.Alias.Replace("-" + newAlias + "_", "-" + oldAlias + "_"); } if (checkAlias == null) { continue; } var checkAliasRecord = aliases.FirstOrDefault(a => a.Alias == checkAlias); if (checkAliasRecord != null) { // swapping! client.Alias(bad => bad.Remove(a => a.Alias(alias.Alias).Index("*")) .Remove(a => a.Alias(checkAliasRecord.Alias).Index("*")) .Add(a => a.Alias(alias.Alias).Index(checkAliasRecord.Index)) .Add(a => a.Alias(checkAliasRecord.Alias).Index(alias.Index))); handled.Add(alias.Alias); handled.Add(checkAliasRecord.Alias); Logger.Warning("Vulcan swapped indexes for aliases: " + alias.Alias + " and " + checkAliasRecord.Alias); } else { // no swap, simply switching this client.Alias(bad => bad.Remove(a => a.Alias(alias.Alias).Index("*")) .Add(a => a.Alias(checkAlias).Index(alias.Index))); Logger.Warning("Vulcan switched index to new indexAlias: " + alias.Alias + " to " + checkAlias); } } } client.Refresh("*"); Clients?.Clear(); // force a client refresh } }
/// <summary> /// Gets synonyms for language /// </summary> /// <returns></returns> public virtual Dictionary <string, KeyValuePair <string[], bool> > GetSynonyms() => VulcanHelper.GetSynonyms(Language.Name);
/// <summary> /// Initialize analyzer on elasticsearch /// </summary> /// <param name="client"></param> protected virtual void InitializeAnalyzer(IVulcanClient client) { var language = VulcanHelper.GetAnalyzer(client.Language); IUpdateIndexSettingsResponse response; if (language != "standard") { // first, stop words response = client.UpdateIndexSettings(client.IndexName, uix => uix .IndexSettings(ixs => ixs .Analysis(ana => ana .TokenFilters(tf => tf .Stop("stop", sw => sw .StopWords(GetStopwordsLanguage(language))))))); if (!response.IsValid) { Logger.Error($"Could not set up stop words for {client.IndexName}: {response.DebugInformation}"); } // next, stemmer if (!new[] { "cjk", "persian", "thai" }.Contains(language)) { response = client.UpdateIndexSettings(client.IndexName, uix => uix .IndexSettings(ixs => ixs .Analysis(ana => ana .TokenFilters(tf => tf .Stemmer("stemmer", stm => stm .Language(GetStemmerLanguage(language))))))); if (!response.IsValid) { Logger.Error($"Could not set up stemmers for {client.IndexName}: {response.DebugInformation}"); } } // next, stemmer overrides if (language == "dutch") { response = client.UpdateIndexSettings(client.IndexName, uix => uix .IndexSettings(ixs => ixs .Analysis(ana => ana .TokenFilters(tf => tf .StemmerOverride("override", stm => stm .Rules("fiets=>fiets", "bromfiets=>bromfiets", "ei=>eier", "kind=>kinder")))))); if (!response.IsValid) { Logger.Error($"Could not set up stemmer overrides for {client.IndexName}: {response.DebugInformation}"); } } // next, elision if (new[] { "catalan", "french", "irish", "italian" }.Contains(language)) { response = client.UpdateIndexSettings(client.IndexName, uix => uix .IndexSettings(ixs => ixs .Analysis(ana => ana .TokenFilters(tf => tf .Elision("elision", e => e .Articles(GetElisionArticles(language))))))); if (!response.IsValid) { Logger.Error($"Could not set up elisions for {client.IndexName}: {response.DebugInformation}"); } } // next, possessive if (language == "english") { response = client.UpdateIndexSettings(client.IndexName, uix => uix .IndexSettings(ixs => ixs .Analysis(ana => ana .TokenFilters(tf => tf .Stemmer("possessive", stm => stm .Language("possessive_english")))))); if (!response.IsValid) { Logger.Error($"Could not set up possessives for {client.IndexName}: {response.DebugInformation}"); } } // next, lowercase if (new[] { "greek", "irish", "turkish" }.Contains(language)) { response = client.UpdateIndexSettings(client.IndexName, uix => uix .IndexSettings(ixs => ixs .Analysis(ana => ana .TokenFilters(tf => tf .Lowercase("custom_lowercase", stm => stm .Language(language)))))); if (!response.IsValid) { Logger.Error("Could not set up lowercases for " + client.IndexName + ": " + response.DebugInformation); } } } response = client.UpdateIndexSettings(client.IndexName, uix => uix .IndexSettings(ixs => ixs .Analysis(ana => ana .TokenFilters(tf => tf .Synonym("synonyms", syn => syn .Synonyms(GetSynonyms(client)))) .Analyzers(a => a .Custom("default", cad => cad .Tokenizer("standard") .Filters(GetFilters(language))))))); if (!response.IsValid) { Logger.Error($"Could not set up custom analyzers for {client.IndexName}: {response.DebugInformation}"); } if (language != "persian") { return; } response = client.UpdateIndexSettings(client.IndexName, uix => uix .IndexSettings(ixs => ixs .Analysis(ana => ana .CharFilters(cf => cf .Mapping("zero_width_spaces", stm => stm .Mappings("\\u200C=> "))) .Analyzers(a => a .Custom("default", cad => cad .CharFilters("zero_width_spaces")))))); if (!response.IsValid) { Logger.Error("Could not set up char filters for " + client.IndexName + ": " + response.DebugInformation); } }
/// <summary> /// Remove a synonym /// </summary> /// <param name="term"></param> public virtual void RemoveSynonym(string term) { VulcanHelper.DeleteSynonym(Language.Name, term); }
/// <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> /// <param name="alias"></param> /// <returns>A Vulcan client</returns> public virtual IVulcanClient GetClient(CultureInfo language = null, string alias = null) { var cultureInfo = language ?? CultureInfo.CurrentUICulture; var aliasSafe = string.IsNullOrWhiteSpace(alias) ? VulcanHelper.MasterAlias : alias; IVulcanClient storedClient; lock (_lockObject) { if (!Clients.ContainsKey(aliasSafe)) { Clients[aliasSafe] = new ConcurrentDictionary <CultureInfo, IVulcanClient>(); } if (Clients[aliasSafe].TryGetValue(cultureInfo, out storedClient)) { return(storedClient); } // todo: need some sort of check here to make sure we still need to create a client var aliasName = VulcanHelper.GetAliasName(Index, cultureInfo, alias); var settings = CommonConnectionSettings.ConnectionSettings; settings.InferMappingFor <ContentMixin>(pd => pd.Ignore(p => p.MixinInstance)); settings.DefaultIndex(aliasName); var client = CreateVulcanClient(Index, alias, settings, cultureInfo); var nodesInfo = client.NodesInfo(); // first let's check our version 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?"); } 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?"); } 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 #if NEST2 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.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() ) )) ) ))))); #elif NEST5 // note: strings are no more in ES5, for not analyzed text use Keyword and for analyzed use Text 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.Keyword(s => s .IgnoreAbove(CreateIndexCustomizer.IgnoreAbove) // needed for: document contains at least one immense term in field .Fields(f => f .Text(ana => ana .Name(VulcanFieldConstants.AnalyzedModifier) .Store() ) )) ) ))))); #endif string actualIndexName = null; if (client.AliasExists(a => a.Name(aliasName)).Exists) { var indices = client.GetAlias(a => a.Name(aliasName)).Indices; if (indices != null) { if (indices.Any()) { actualIndexName = indices.First().Key; } } } if (actualIndexName == null) { actualIndexName = VulcanHelper.GetRawIndexName(Index, cultureInfo); var response = client.CreateIndex(actualIndexName, CreateIndexCustomizer.CustomizeIndex); if (!response.IsValid) { Logger.Error("Could not create index " + actualIndexName + ": " + response.DebugInformation); } else { // set up the indexAlias client.PutAlias(actualIndexName, aliasName); } } client.Refresh(actualIndexName); var closeResponse = client.CloseIndex(actualIndexName); if (!closeResponse.IsValid) { Logger.Error("Could not close index " + actualIndexName + ": " + closeResponse.DebugInformation); } InitializeAnalyzer(client); // run installers foreach (var installer in _vulcanPipelineInstallers) { installer.Install(client); } // allows for customizations client.RunCustomizers(Logger); client.RunCustomMappers(Logger); client.OpenIndex(actualIndexName); if (CreateIndexCustomizer.WaitForActiveShards > 0) { // Init shards to attempt to fix empty results on first request client.ClusterHealth(x => x.WaitForActiveShards( #if NEST2 CreateIndexCustomizer.WaitForActiveShards #elif NEST5 CreateIndexCustomizer.WaitForActiveShards.ToString() #endif )); } storedClient = client; } // ReSharper disable once InconsistentlySynchronizedField Clients[aliasSafe][cultureInfo] = storedClient; return(storedClient); }
/// <summary> /// Adds a synonym /// </summary> /// <param name="term"></param> /// <param name="synonyms"></param> /// <param name="biDirectional"></param> public virtual void AddSynonym(string term, string[] synonyms, bool biDirectional) { VulcanHelper.AddSynonym(Language.Name, term, synonyms, biDirectional); }
/// <summary> /// Index item /// </summary> /// <param name="pocoIndexer"></param> /// <param name="updateStatus"></param> /// <param name="count"></param> /// <param name="stopSignaled"></param> /// <param name="alias"></param> /// <returns></returns> public virtual string Index(IVulcanPocoIndexer pocoIndexer, Action <string> updateStatus, ref int count, ref bool stopSignaled, string alias = null) { if (pocoIndexer == null) { throw new ArgumentNullException($"{nameof(pocoIndexer)} cannot be null!"); } VulcanHelper.GuardForNullAlias(ref alias); var total = pocoIndexer.TotalItems; var pageSize = pocoIndexer.PageSize; pageSize = pageSize < 1 ? 1 : pageSize; // don't allow 0 or negative var totalPages = (total + pageSize - 1) / pageSize; var internalCount = 0; var invariantClient = GetInvariantClient(alias); for (var page = 1; page <= totalPages; page++) { updateStatus?.Invoke($"Indexing page {page} of {totalPages} items of {pocoIndexer.IndexerName} content!"); var itemsToIndex = pocoIndexer.GetItems(page, pageSize)?.ToList(); var firstItem = itemsToIndex?.FirstOrDefault(); if (firstItem == null) { break; } var itemType = firstItem.GetType(); var itemTypeName = GetTypeName(firstItem); var operationType = typeof(BulkIndexOperation <>).MakeGenericType(itemType); var operations = new List <IBulkOperation>(); foreach (var item in itemsToIndex) { if (stopSignaled) { return("Stop of job was called"); } if (!(Activator.CreateInstance(operationType, item) is IBulkOperation indexItem)) { throw new Exception("Unable to create item for bulk request"); } indexItem.Type = new TypeName { Name = itemTypeName, Type = itemType }; indexItem.Id = pocoIndexer.GetItemIdentifier(item); operations.Add(indexItem); internalCount++; count++; } // https://www.elastic.co/guide/en/elasticsearch/client/net-api/1.x/bulk.html var request = new BulkRequest { #if NEST2 Refresh = true, Consistency = Consistency.One, #elif NEST5 Refresh = Refresh.True, #endif Operations = operations }; invariantClient.Bulk(request); } return($"Indexed {internalCount} of {total} items of {pocoIndexer.IndexerName} content!"); }
/// <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> /// invariant client /// </summary> protected IVulcanClient GetInvariantClient(string alias = null) { VulcanHelper.GuardForNullAlias(ref alias); return(VulcanHander.GetClient(CultureInfo.InvariantCulture, alias)); }