-
Notifications
You must be signed in to change notification settings - Fork 43
Expand file tree
/
Copy pathElasticsearchClientAccessor.cs
More file actions
106 lines (90 loc) · 3.87 KB
/
ElasticsearchClientAccessor.cs
File metadata and controls
106 lines (90 loc) · 3.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information
using Elastic.Clients.Elasticsearch;
using Elastic.Clients.Elasticsearch.Serialization;
using Elastic.Documentation.Configuration;
using Elastic.Documentation.Configuration.Search;
using Elastic.Documentation.Search;
using Elastic.Transport;
namespace Elastic.Documentation.Search.Common;
/// <summary>
/// Shared singleton accessor for the Elasticsearch client.
/// Both Navigation Search (autocomplete) and FullSearch gateways share this client instance.
/// </summary>
public class ElasticsearchClientAccessor : IDisposable
{
private readonly ElasticsearchClientSettings _clientSettings;
private readonly SingleNodePool _nodePool;
public ElasticsearchClient Client { get; }
public ElasticsearchEndpoint Endpoint { get; }
public SearchConfiguration SearchConfiguration { get; }
/// <summary>
/// Index target for search queries. When <c>DOCUMENTATION_ELASTIC_INDEX_OVERRIDE</c> is set,
/// this contains the override value (which may be comma-separated for multiple indices);
/// otherwise it is derived from <see cref="DocumentationEndpoints.BuildType"/> and <see cref="DocumentationEndpoints.Environment"/>.
/// </summary>
public string SearchIndex { get; }
public string? RulesetName { get; }
public IReadOnlyDictionary<string, string[]> SynonymBiDirectional { get; }
public IReadOnlyCollection<string> DiminishTerms { get; }
public ElasticsearchClientAccessor(
DocumentationEndpoints endpoints,
SearchConfiguration searchConfiguration
)
{
var endpoint = endpoints.Elasticsearch;
Endpoint = endpoint;
SearchConfiguration = searchConfiguration;
SynonymBiDirectional = searchConfiguration.SynonymBiDirectional;
DiminishTerms = searchConfiguration.DiminishTerms;
var computedIndex = DocumentationMappingContext.DocumentationDocumentSemantic
.CreateContext(type: endpoints.BuildType, env: endpoints.Environment)
.ResolveReadTarget();
SearchIndex = !string.IsNullOrEmpty(endpoints.SearchIndexOverride)
? endpoints.SearchIndexOverride
: computedIndex;
RulesetName = searchConfiguration.Rules.Count > 0
? $"docs-ruleset-{endpoints.BuildType}-{endpoints.Environment}"
: null;
_nodePool = new SingleNodePool(endpoint.Uri);
var auth = endpoint.ApiKey is { } apiKey
? (AuthorizationHeader)new ApiKey(apiKey)
: endpoint is { Username: { } username, Password: { } password }
? new BasicAuthentication(username, password)
: null!;
_clientSettings = new ElasticsearchClientSettings(
_nodePool,
sourceSerializer: (_, settings) => new DefaultSourceSerializer(settings, EsJsonContext.Default)
)
.DefaultIndex(SearchIndex)
.Authentication(auth);
Client = new ElasticsearchClient(_clientSettings);
}
/// <summary>
/// Extracts the ruleset name from the index name.
/// Index name format: "semantic-docs-{namespace}-latest" -> ruleset: "docs-ruleset-{namespace}"
/// The namespace may contain hyphens (e.g., "codex-internal"), so we extract everything
/// between the "semantic-docs-" prefix and the "-latest" suffix.
/// </summary>
private static string? ExtractRulesetName(string indexName)
{
const string prefix = "semantic-docs-";
const string suffix = "-latest";
if (!indexName.StartsWith(prefix, StringComparison.Ordinal) || !indexName.EndsWith(suffix, StringComparison.Ordinal))
return null;
var ns = indexName[prefix.Length..^suffix.Length];
return string.IsNullOrEmpty(ns) ? null : $"docs-ruleset-{ns}";
}
/// <summary>
/// Tests connectivity to the Elasticsearch cluster.
/// </summary>
public async Task<bool> CanConnect(Cancel ctx) => (await Client.PingAsync(ctx)).IsValidResponse;
/// <inheritdoc />
public void Dispose()
{
GC.SuppressFinalize(this);
((IDisposable)_clientSettings).Dispose();
_nodePool.Dispose();
}
}