Skip to content

Commit 0e5357e

Browse files
committed
update documentation
1 parent e37e37d commit 0e5357e

20 files changed

+498
-151
lines changed

docs/aggregations/writing-aggregations.asciidoc

Lines changed: 71 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,14 @@ new SearchRequest<Project>
9898
{
9999
Aggregations = new AggregationDictionary
100100
{
101-
{ "name_of_child_agg", new ChildrenAggregation("name_of_child_agg", typeof(CommitActivity))
101+
{
102+
"name_of_child_agg", new ChildrenAggregation("name_of_child_agg", typeof(CommitActivity))
102103
{
103104
Aggregations = new AggregationDictionary
104105
{
105-
{ "average_per_child", new AverageAggregation("average_per_child", "confidenceFactor") },
106-
{ "max_per_child", new MaxAggregation("max_per_child", "confidenceFactor") },
107-
{ "min_per_child", new MinAggregation("min_per_child", "confidenceFactor") },
106+
{"average_per_child", new AverageAggregation("average_per_child", "confidenceFactor")},
107+
{"max_per_child", new MaxAggregation("max_per_child", "confidenceFactor")},
108+
{"min_per_child", new MinAggregation("min_per_child", "confidenceFactor")},
108109
}
109110
}
110111
}
@@ -143,52 +144,91 @@ Now that's much cleaner! Assigning an `*Aggregation` type directly to the `Aggre
143144
on a search request works because there are implicit conversions within NEST to handle this for you.
144145

145146
[float]
146-
=== Aggregating over a collection of aggregations
147+
=== Mixed usage of object initializer and fluent
147148

148-
An advanced scenario may involve an existing collection of aggregation functions that should be set as aggregations
149-
on the request. Using LINQ's `.Aggregate()` method, each function can be applied to the aggregation descriptor
150-
`childAggs` below) in turn, returning the descriptor after each function application.
149+
Sometimes its useful to mix and match fluent and object initializer, the fluent Aggregations method therefore
150+
also accepts `AggregationDictionary` directly.
151151

152152
==== Fluent DSL example
153153

154154
[source,csharp]
155155
----
156-
var aggregations = new List<Func<AggregationContainerDescriptor<CommitActivity>, IAggregationContainer>> <1>
156+
s => s
157+
.Aggregations(new ChildrenAggregation("name_of_child_agg", typeof(CommitActivity))
157158
{
158-
a => a.Average("average_per_child", avg => avg.Field(p => p.ConfidenceFactor)),
159-
a => a.Max("max_per_child", avg => avg.Field(p => p.ConfidenceFactor)),
160-
a => a.Min("min_per_child", avg => avg.Field(p => p.ConfidenceFactor))
161-
};
159+
Aggregations =
160+
new AverageAggregation("average_per_child", Field<CommitActivity>(p => p.ConfidenceFactor))
161+
&& new MaxAggregation("max_per_child", Field<CommitActivity>(p => p.ConfidenceFactor))
162+
&& new MinAggregation("min_per_child", Field<CommitActivity>(p => p.ConfidenceFactor))
163+
})
164+
----
162165

163-
return s => s
164-
.Aggregations(aggs => aggs
165-
.Children<CommitActivity>("name_of_child_agg", child => child
166-
.Aggregations(childAggs =>
167-
aggregations.Aggregate(childAggs, (acc, agg) => { agg(acc); return acc; }) <2>
168-
)
169-
)
170-
);
166+
[float]
167+
=== Binary operators off the same descriptor
168+
169+
For dynamic aggregation building using the fluent syntax it can be useful to abstract to methods as much as possible.
170+
You can use the binary operator `&&` on the same descriptor to compose the graph. Each side of the
171+
binary operation can return null dynamically.
172+
173+
[source,csharp]
174+
----
175+
s => s
176+
.Aggregations(aggs => aggs
177+
.Children<CommitActivity>("name_of_child_agg", child => child
178+
.Aggregations(Combine)
179+
)
180+
)
171181
----
172-
<1> a list of aggregation functions to apply
173-
<2> Using LINQ's `Aggregate()` function to accumulate/apply all of the aggregation functions
174182

175-
Combining multiple `AggregationDescriptor` is also possible using the bitwise `&&` operator
183+
[float]
184+
=== Returning a different AggregationContainer in fluent syntax
185+
186+
All the fluent selector expects is an `IAggregationContainer` to be returned. You could abstract this to a
187+
method returning `AggregationContainer` which is free to use the object initializer syntax
188+
to compose that `AggregationContainer`.
189+
190+
[source,csharp]
191+
----
192+
s => s
193+
.Aggregations(aggs => aggs
194+
.Children<CommitActivity>("name_of_child_agg", child => child
195+
.Aggregations(childAggs => Combine())
196+
)
197+
)
198+
----
199+
200+
[float]
201+
=== Aggregating over a collection of aggregations
202+
203+
An advanced scenario may involve an existing collection of aggregation functions that should be set as aggregations
204+
on the request. Using LINQ's `.Aggregate()` method, each function can be applied to the aggregation descriptor
205+
`childAggs` below) in turn, returning the descriptor after each function application.
176206

177207
[source,csharp]
178208
----
179-
var aggregations = new AggregationContainerDescriptor<CommitActivity>()
180-
.Average("average_per_child", avg => avg.Field(p => p.ConfidenceFactor))
181-
.Max("max_per_child", avg => avg.Field(p => p.ConfidenceFactor))
182-
&& new AggregationContainerDescriptor<CommitActivity>()
183-
.Min("min_per_child", avg => avg.Field(p => p.ConfidenceFactor));
209+
var aggregations =
210+
new List<Func<AggregationContainerDescriptor<CommitActivity>, IAggregationContainer>> <1>
211+
{
212+
a => a.Average("average_per_child", avg => avg.Field(p => p.ConfidenceFactor)),
213+
a => a.Max("max_per_child", avg => avg.Field(p => p.ConfidenceFactor)),
214+
a => a.Min("min_per_child", avg => avg.Field(p => p.ConfidenceFactor))
215+
};
184216
185217
return s => s
186218
.Aggregations(aggs => aggs
187219
.Children<CommitActivity>("name_of_child_agg", child => child
188-
.Aggregations(childAggs => aggregations)
220+
.Aggregations(childAggs =>
221+
aggregations.Aggregate(childAggs, (acc, agg) =>
222+
{
223+
agg(acc);
224+
return acc;
225+
}) <2>
226+
)
189227
)
190228
);
191229
----
230+
<1> a list of aggregation functions to apply
231+
<2> Using LINQ's `Aggregate()` function to accumulate/apply all of the aggregation functions
192232

193233
[[aggs-vs-aggregations]]
194234
[float]
@@ -222,7 +262,7 @@ the `Average` and `Max` sub aggregations.
222262

223263
[source,csharp]
224264
----
225-
response.IsValid.Should().BeTrue();
265+
response.ShouldBeValid();
226266
227267
var childAggregation = response.Aggs.Children("name_of_child_agg");
228268

docs/client-concepts/certificates/working-with-certificates.asciidoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ You can set Client Certificates to use on all connections on `ConnectionSettings
133133
----
134134
public class PkiCluster : CertgenCaCluster
135135
{
136-
public override ConnectionSettings Authenticate(ConnectionSettings s) => s <1>
136+
protected override ConnectionSettings Authenticate(ConnectionSettings s) => s <1>
137137
.ClientCertificate(
138138
ClientCertificate.LoadWithPrivateKey(
139139
this.Node.FileSystem.ClientCertificate, <2>

docs/client-concepts/connection-pooling/building-blocks/connection-pooling.asciidoc

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,3 +241,41 @@ client.ConnectionSettings.ConnectionPool
241241
.Should().BeOfType<StickyConnectionPool>();
242242
----
243243

244+
[[sticky-sniffing-connection-pool]]
245+
==== Sticky Sniffing Connection Pool
246+
247+
A type of connection pool that returns the first live node to issue a request against, such that the node is _sticky_ between requests.
248+
This implementation supports sniffing and sorting so that each instance of your application can favor a node in the same rack based
249+
on node attributes for instance.
250+
251+
[source,csharp]
252+
----
253+
var uris = Enumerable.Range(9200, 5)
254+
.Select(port => new Uri($"http://localhost:{port}"));
255+
----
256+
257+
a sniffing sorted sticky pool takes a second parameter `Func` takes a Node and returns a weight.
258+
Nodes will be sorted descending by weight. In the following example we score nodes that are client nodes
259+
AND in rack_id `rack_one` the highest
260+
261+
[source,csharp]
262+
----
263+
var pool = new StickySniffingConnectionPool(uris, n =>
264+
(n.ClientNode ? 10 : 0)
265+
+ (n.Settings.TryGetValue("node.attr.rack_id", out string rackId)
266+
&& rackId == "rack_one" ? 10 : 0));
267+
268+
pool.SupportsReseeding.Should().BeTrue();
269+
pool.SupportsPinging.Should().BeTrue();
270+
----
271+
272+
To create a client using the sticky sniffing connection pool pass
273+
the connection pool to the `ConnectionSettings` you pass to `ElasticClient`
274+
275+
[source,csharp]
276+
----
277+
var client = new ElasticClient(new ConnectionSettings(pool));
278+
client.ConnectionSettings.ConnectionPool
279+
.Should().BeOfType<StickySniffingConnectionPool>();
280+
----
281+

docs/client-concepts/connection-pooling/building-blocks/transports.asciidoc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ please modify the original csharp file found at the link and submit the PR with
1515
[[transports]]
1616
=== Transports
1717

18-
The `ITransport` interface can be seen as the motor block of the client. Its interface is
18+
The `ITransport` interface can be seen as the motor block of the client. Its interface is
1919
deceitfully simple, yet it's ultimately responsible for translating a client call to a response.
2020

2121
If for some reason you do not agree with the way we wrote the internals of the client,
@@ -51,12 +51,12 @@ custom `ITransport` implementation and if you do, {github}/issues[please let us
5151
var response = inMemoryTransport.Request<SearchResponse<Project>>(
5252
HttpMethod.GET,
5353
"/_search",
54-
new { query = new { match_all = new { } } });
54+
PostData.Serializable(new { query = new { match_all = new { } } }));
5555
5656
response = await inMemoryTransport.RequestAsync<SearchResponse<Project>>(
5757
HttpMethod.GET,
5858
"/_search",
5959
default(CancellationToken),
60-
new { query = new { match_all = new { } } });
60+
PostData.Serializable(new { query = new { match_all = new { } } }));
6161
----
6262

docs/client-concepts/connection-pooling/exceptions/unrecoverable-exceptions.asciidoc

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,21 +89,21 @@ audit = await audit.TraceElasticsearchException(
8989
<2> Second call results in a bad response
9090
<3> The reason for the bad response is Bad Authentication
9191

92-
When a bad authentication response occurs, the client does not attempt to deserialize the response body returned;
93-
The response may or may not have a body and even when it does, it may not even be JSON.
92+
When a bad authentication response occurs, the client attempts to deserialize the response body returned;
9493

95-
In the following couple of examples, we set up a cluster that always returns a typical nginx HTML response body
96-
with 401 response to client calls. In this first example, we assert that the failure is because of a 401 Bad Authentication
97-
response but the response body is not captured on the response
94+
In some setups you might be running behind a proxy and you might need to prevent the client from trying to deserialize
95+
bad json. In the following example an HTML response is return but with an application/json content type. If the proxy is not
96+
under your control you would need to be able to fix this in the client. Here we make the client aware that 401 responses
97+
should never be deserialized by calling `SkipDeserializationForStatusCodes()` on `ConnectionSettings`.
9898

9999
[source,csharp]
100100
----
101101
var audit = new Auditor(() => Framework.Cluster
102102
.Nodes(10)
103103
.Ping(r => r.SucceedAlways())
104-
.ClientCalls(r => r.FailAlways(401).ReturnResponse(HtmlNginx401Response)) <1>
104+
.ClientCalls(r => r.FailAlways(401).ReturnByteResponse(HtmlNginx401Response, "application/json")) <1>
105105
.StaticConnectionPool()
106-
.AllDefaults()
106+
.Settings(s=>s.SkipDeserializationForStatusCodes(401))
107107
);
108108
109109
audit = await audit.TraceElasticsearchException(
@@ -124,13 +124,15 @@ audit = await audit.TraceElasticsearchException(
124124

125125
Now in this example, by turning on `DisableDirectStreaming()` on `ConnectionSettings`, we see the same behaviour exhibited
126126
as before, but this time however, the response body bytes are captured in the response and can be inspected.
127+
Also note that in this example the 401 returns the correct mime type for html so the client wont try to deserialize to json and
128+
we no longer need to set `SkipDeserializationForStatusCodes()`
127129

128130
[source,csharp]
129131
----
130132
var audit = new Auditor(() => Framework.Cluster
131133
.Nodes(10)
132134
.Ping(r => r.SucceedAlways())
133-
.ClientCalls(r => r.FailAlways(401).ReturnResponse(HtmlNginx401Response))
135+
.ClientCalls(r => r.FailAlways(401).ReturnByteResponse(HtmlNginx401Response, "text/html"))
134136
.StaticConnectionPool()
135137
.Settings(s => s.DisableDirectStreaming())
136138
);

0 commit comments

Comments
 (0)