Elasticsearch(十二)【NEST高级客户端--规范】
来源:互联网 发布:淘宝q币充值改金额 编辑:程序博客网 时间:2024/05/18 00:42
规范
NEST有一些规范用于推理
文档路径API功能字段IDS索引名称索引路径属性
文档路径
Elasticsearch中的许多API描述了一个文档的路径。 在NEST中,除了生成一个构造函数之外,还分别创建了Index,Type和Id,我们还生成一个构造函数,可以使用DocumentPath<T>
类型的实例更简洁地描述文档的路径。
创建新实例
这里我们创建一个基于项目的id为1的新文档路径
IDocumentPath path = new DocumentPath<Project>(1);Expect("project").WhenSerializing(path.Index);Expect("project").WhenSerializing(path.Type);Expect(1).WhenSerializing(path.Id);
您仍然可以覆盖推断索引和类型名称
path = new DocumentPath<Project>(1).Type("project1");Expect("project1").WhenSerializing(path.Type);path = new DocumentPath<Project>(1).Index("project1");Expect("project1").WhenSerializing(path.Index);
并且还有一种静态方式来描述这样的路径
path = DocumentPath<Project>.Id(1);Expect("project").WhenSerializing(path.Index);Expect("project").WhenSerializing(path.Type);Expect(1).WhenSerializing(path.Id);
从文档类型实例创建
如果您有一个文档的实例,您也可以使用它来生成文档路径
var project = new Project { Name = "hello-world" };
这里我们根据Project
,project的实例创建一个新的文档路径
IDocumentPath path = new DocumentPath<Project>(project);Expect("project").WhenSerializing(path.Index);Expect("project").WhenSerializing(path.Type);Expect("hello-world").WhenSerializing(path.Id);
您仍然可以覆盖推断索引和类型名称
path = new DocumentPath<Project>(project).Type("project1");Expect("project1").WhenSerializing(path.Type);path = new DocumentPath<Project>(project).Index("project1");Expect("project1").WhenSerializing(path.Index);
而且,还有一种描述这种路径的静态方式
path = DocumentPath<Project>.Id(project);Expect("project").WhenSerializing(path.Index);Expect("project").WhenSerializing(path.Type);Expect("hello-world").WhenSerializing(path.Id);DocumentPath<Project> p = project;
具有请求的示例
var project = new Project { Name = "hello-world" };
我们可以看到DocumentPath
如何帮助您更简单地描述您的请求的示例
var request = new IndexRequest<Project>(2) { Document = project };request = new IndexRequest<Project>(project) { };
当与完整的构造函数和手动通过文档进行比较时,DocumentPath
的优点变得明显。 将以下不使用DocumentPath<T>
的请求与前面的示例进行比较
request = new IndexRequest<Project>(IndexName.From<Project>(), TypeName.From<Project>(), 2){ Document = project};
特征推论
Elasticsearch中的一些URI采用了功能枚举。 在NEST中,URI上的路由值表示为实现接口IUrlParameter
的类。 由于枚举不能在C#中实现接口,所以将使用Feature
枚举隐式转换为的Features
类来表示Feature
类型的路由参数。
构造函数
直接使用Features
构造函数是可行的,而是涉及到
Features fieldString = Feature.Mappings | Feature.Aliases;Expect("_mappings,_aliases") .WhenSerializing(fieldString);
这里我们新建一个GET索引elasticsearch 请求,它需要Indices和Features。 注意我们如何直接使用Feature枚举。
var request = new GetIndexRequest(All, Feature.Settings);
字段推测
Elasticsearch API中的几个地方期望从原始源文档中的字段的路径作为字符串值。 NEST允许您使用C#表达式来强烈地键入这些字段路径字符串。
这些表达式分配给一个名为Field
的类型,并且有几种方法来创建一个实例
构造函数
直接使用构造函数是可行的,但是当从成员访问lambda表达式解析时可以相当的参与
var fieldString = new Field("name");var fieldProperty = new Field(typeof(Project).GetProperty(nameof(Project.Name)));Expression<Func<Project, object>> expression = p => p.Name;var fieldExpression = new Field(expression);Expect("name") .WhenSerializing(fieldExpression) .WhenSerializing(fieldString) .WhenSerializing(fieldProperty);When using the constructor and passing a value for Name, Property or Expression, ComparisonValue is also set on the Field instance; this is used when determining Field equality getting the hash code for a Field instance ImportantBoost values are not taken into account when determining equality.var fieldStringWithBoostTwo = new Field("name^2");var fieldStringWithBoostThree = new Field("name^3");Expression<Func<Project, object>> expression = p => p.Name;var fieldExpression = new Field(expression);var fieldProperty = new Field(typeof(Project).GetProperty(nameof(Project.Name)));fieldStringWithBoostTwo.GetHashCode().Should().NotBe(0);fieldStringWithBoostThree.GetHashCode().Should().NotBe(0);fieldExpression.GetHashCode().Should().NotBe(0);fieldProperty.GetHashCode().Should().NotBe(0);fieldStringWithBoostTwo.Should().Be(fieldStringWithBoostThree);
字段名称与Boost
当指定Field
名称时,该名称可以包括boost值; NEST将拆分名称和提升值并设置Boost
属性; 作为字符串一部分的boost值优先于可以作为第二个构造函数参数传递的boost值
Field fieldString = "name^2";Field fieldStringConstructor = new Field("name^2");Field fieldStringCreate = new Field("name^2", 3); fieldString.Name.Should().Be("name");fieldStringConstructor.Name.Should().Be("name");fieldStringCreate.Name.Should().Be("name");fieldString.Boost.Should().Be(2);fieldStringConstructor.Boost.Should().Be(2);fieldStringCreate.Boost.Should().Be(2);
隐性转换
除了使用构造函数,您还可以将string
,PropertyInfo
和成员访问lambda表达式隐式转换为Field
。 然而,对于表达式,这仍然是相当重要的,因为表达式首先需要分配给明确指定表达式委托类型的变量。
Field fieldString = "name";Field fieldProperty = typeof(Project).GetProperty(nameof(Project.Name));Expression<Func<Project, object>> expression = p => p.Name;Field fieldExpression = expression;Expect("name") .WhenSerializing(fieldString) .WhenSerializing(fieldProperty) .WhenSerializing(fieldExpression);
使用Nest.Infer方法
为了简化从表达式创建一个Field实例,可以使用一个静态Infer类
此示例使用静态导入using static Nest.Infer;
在使用指令中将Nest.Infer.Field<T>()
简化为Field<T>()
。 如果复制任何这些示例,请确保包含此静态导入
Field fieldString = "name";
但是对于表达式来说,这仍然是相当涉及的
var fieldExpression = Infer.Field<Project>(p => p.Name);
这甚至可以使用静态导入进一步缩短。 现在我们第一个使用构造函数的例子更简单了!
fieldExpression = Field<Project>(p => p.Name);Expect("name") .WhenSerializing(fieldString) .WhenSerializing(fieldExpression);
您可以使用字符串以及使用Nest.Infer.Field
在字段中指定boosts
fieldString = "name^2.1";fieldString.Boost.Should().Be(2.1);fieldExpression = Field<Project>(p => p.Name, 2.1);fieldExpression.Boost.Should().Be(2.1);Expect("name^2.1") .WhenSerializing(fieldString) .WhenSerializing(fieldExpression);
字段命名风格
默认情况下,NEST可以使所有字段名称更好地与典型的JavaScript和JSON约定相一致
在ConnectionSettings
上使用DefaultFieldNameInferrer()
,可以更改此行为
var setup = WithConnectionSettings(s => s.DefaultFieldNameInferrer(p => p.ToUpper()));setup.Expect("NAME").WhenSerializing(Field<Project>(p => p.Name));
然而,string
类型始终是逐字逐行传递的
setup.Expect("NaMe").WhenSerializing<Field>("NaMe");
您希望表达式具有相同的行为,只需将Func<string,string>
传递给DefaultFieldNameInferrer
即可更改名称
setup = WithConnectionSettings(s => s.DefaultFieldNameInferrer(p => p));setup.Expect("Name").WhenSerializing(Field<Project>(p => p.Name));
复杂字段名称表达式
您可以按照您的属性表达任何深度。 这里我们正在遍历LeadDeveloper FirstName
Expect("leadDeveloper.firstName").WhenSerializing(Field<Project>(p => p.LeadDeveloper.FirstName));
处理集合索引器时,索引器访问被忽略,允许您遍历集合的属性
Expect("curatedTags").WhenSerializing(Field<Project>(p => p.CuratedTags[0]));
同样,LINQ的.First()
方法也可以
Expect("curatedTags").WhenSerializing(Field<Project>(p => p.CuratedTags.First()));Expect("curatedTags.added").WhenSerializing(Field<Project>(p => p.CuratedTags[0].Added));Expect("curatedTags.name").WhenSerializing(Field<Project>(p => p.CuratedTags.First().Name));
记住,这些是表达式,而不是将被执行的实际代码
假设字典上的索引器描述属性名称
Expect("metadata.hardcoded").WhenSerializing(Field<Project>(p => p.Metadata["hardcoded"]));Expect("metadata.hardcoded.created").WhenSerializing(Field<Project>(p => p.Metadata["hardcoded"].Created));
这里的一个很酷的功能是NEST将评估传递给索引器的变量
var variable = "var";Expect("metadata.var").WhenSerializing(Field<Project>(p => p.Metadata[variable]));Expect("metadata.var.created").WhenSerializing(Field<Project>(p => p.Metadata[variable].Created));
如果您使用Elasticearch的多字段,那么您真的应该使用它们,因为它们允许您以多种不同的方式分析字符串,这些”virtual”子字段并不总是映射到您的POCO。 通过在表达式上调用.Suffix()
,可以描述应该映射的子字段以及它们的映射方式
Expect("leadDeveloper.firstName.raw").WhenSerializing( Field<Project>(p => p.LeadDeveloper.FirstName.Suffix("raw")));Expect("curatedTags.raw").WhenSerializing( Field<Project>(p => p.CuratedTags[0].Suffix("raw")));Expect("curatedTags.raw").WhenSerializing( Field<Project>(p => p.CuratedTags.First().Suffix("raw")));Expect("curatedTags.added.raw").WhenSerializing( Field<Project>(p => p.CuratedTags[0].Added.Suffix("raw")));Expect("metadata.hardcoded.raw").WhenSerializing( Field<Project>(p => p.Metadata["hardcoded"].Suffix("raw")));Expect("metadata.hardcoded.created.raw").WhenSerializing( Field<Project>(p => p.Metadata["hardcoded"].Created.Suffix("raw")));
你甚至可以链接.Suffix()
调用任何深度!
Expect("curatedTags.name.raw.evendeeper").WhenSerializing( Field<Project>(p => p.CuratedTags.First().Name.Suffix("raw").Suffix("evendeeper")));
传递给后缀的变量也将被评估
var suffix = "unanalyzed";Expect("metadata.var.unanalyzed").WhenSerializing( Field<Project>(p => p.Metadata[variable].Suffix(suffix)));Expect("metadata.var.created.unanalyzed").WhenSerializing( Field<Project>(p => p.Metadata[variable].Created.Suffix(suffix)));
后缀也可以使用.AppendSuffix()
附加到表达式。 在您要将相同后缀应用于字段列表的情况下,这是非常有用的。
这里我们有一个表达式列表
var expressions = new List<Expression<Func<Project, object>>>{ p => p.Name, p => p.Description, p => p.CuratedTags.First().Name, p => p.LeadDeveloper.FirstName, p => p.Metadata["hardcoded"]};
并且我们要为每个添加后缀“raw”
var fieldExpressions = expressions.Select<Expression<Func<Project, object>>, Field>(e => e.AppendSuffix("raw")).ToList();Expect("name.raw").WhenSerializing(fieldExpressions[0]);Expect("description.raw").WhenSerializing(fieldExpressions[1]);Expect("curatedTags.name.raw").WhenSerializing(fieldExpressions[2]);Expect("leadDeveloper.firstName.raw").WhenSerializing(fieldExpressions[3]);Expect("metadata.hardcoded.raw").WhenSerializing(fieldExpressions[4]);
或者我们甚至可能想链接多个.AppendSuffix()
调用
var multiSuffixFieldExpressions = expressions.Select<Expression<Func<Project, object>>, Field>(e => e.AppendSuffix("raw").AppendSuffix("evendeeper")).ToList();Expect("name.raw.evendeeper").WhenSerializing(multiSuffixFieldExpressions[0]);Expect("description.raw.evendeeper").WhenSerializing(multiSuffixFieldExpressions[1]);Expect("curatedTags.name.raw.evendeeper").WhenSerializing(multiSuffixFieldExpressions[2]);Expect("leadDeveloper.firstName.raw.evendeeper").WhenSerializing(multiSuffixFieldExpressions[3]);Expect("metadata.hardcoded.raw.evendeeper").WhenSerializing(multiSuffixFieldExpressions[4]);
基于属性的命名
使用NEST的属性特性可以为属性指定一个新名称
public class BuiltIn{ [Text(Name = "naam")] public string Name { get; set; }}Expect("naam").WhenSerializing(Field<BuiltIn>(p => p.Name));
从NEST 2.x开始,我们还要求序列化程序是否可以将属性解析为名称。 在这里,我们要求默认的JsonNetSerializer
解析一个属性名称,并将JsonPropertyAttribute
考虑在内
public class SerializerSpecific{ [JsonProperty("nameInJson")] public string Name { get; set; }}Expect("nameInJson").WhenSerializing(Field<SerializerSpecific>(p => p.Name));
如果属性中都存在NEST属性特性和序列化器特定属性,则NEST属性优先
public class Both{ [Text(Name = "naam")] [JsonProperty("nameInJson")] public string Name { get; set; }}Expect("naam").WhenSerializing(Field<Both>(p => p.Name));Expect(new { naam = "Martijn Laarman" }).WhenSerializing(new Both { Name = "Martijn Laarman" });
字段推测缓存
每个连接设置实例缓存字段名称的解析。 为了演示,请采取以下简单的POCO
class A { public C C { get; set; } }class B { public C C { get; set; } }class C{ public string Name { get; set; }}var client = TestClient.Default;var fieldNameOnA = client.Infer.Field(Field<A>(p => p.C.Name));var fieldNameOnB = client.Infer.Field(Field<B>(p => p.C.Name));
这里我们有两个类似形状的表达式,一个来自A,一个来自B,将按照预期解析为相同的字段名称
fieldNameOnA.Should().Be("c.name");fieldNameOnB.Should().Be("c.name");
现在,当我们在A
上解析属性C
的字段路径时,现在我们创建一个新的连接设置,使用A
类的C
映射到"d"
,这与B
上的属性C
不同
var newConnectionSettings = TestClient.CreateSettings(modifySettings: s => s .InferMappingFor<A>(m => m .Rename(p => p.C, "d") ));var newClient = new ElasticClient(newConnectionSettings);fieldNameOnA = newClient.Infer.Field(Field<A>(p => p.C.Name));fieldNameOnB = newClient.Infer.Field(Field<B>(p => p.C.Name));fieldNameOnA.Should().Be("d.name");fieldNameOnB.Should().Be("c.name");
然而,我们并没有使用其单独的连接设置来破坏第一个客户端实例的推断
fieldNameOnA = client.Infer.Field(Field<A>(p => p.C.Name));fieldNameOnB = client.Infer.Field(Field<B>(p => p.C.Name));fieldNameOnA.Should().Be("c.name");fieldNameOnB.Should().Be("c.name");
推理优先
要包装,推断字段名称的优先级为:
使用`.Rename()`连接设置上的属性的硬编码重命名 NEST属性映射 询问序列化器是否具有逐字数值,例如它具有显式的`JsonProperty`属性。 将MemberInfo的名称传递给`DefaultFieldNameInferrer`,默认情况下为camelCases
以下示例类将演示此优先级
class Precedence{ [Text(Name = "renamedIgnoresNest")] [JsonProperty("renamedIgnoresJsonProperty")] public string RenamedOnConnectionSettings { get; set; } [Text(Name = "nestAtt")] [JsonProperty("jsonProp")] public string NestAttribute { get; set; } [JsonProperty("jsonProp")] public string JsonProperty { get; set; } [JsonProperty("dontaskme")] public string AskSerializer { get; set; } public string DefaultFieldNameInferrer { get; set; } }
在这里,我们创建一个自定义序列化器,重命名任何名为AskSerializer
的属性为ask
class CustomSerializer : JsonNetSerializer{ public CustomSerializer(IConnectionSettingsValues settings) : base(settings) { } public override IPropertyMapping CreatePropertyMapping(MemberInfo memberInfo) { return memberInfo.Name == nameof(Precedence.AskSerializer) ? new PropertyMapping { Name = "ask" } : base.CreatePropertyMapping(memberInfo); }}
在这里,我们使用.Rename()
对ConnectionSettings
上的属性进行显式重命名,并且不会逐字地映射的所有属性应该是大写
var usingSettings = WithConnectionSettings(s => s .InferMappingFor<Precedence>(m => m .Rename(p => p.RenamedOnConnectionSettings, "renamed") ) .DefaultFieldNameInferrer(p => p.ToUpperInvariant())).WithSerializer(s => new CustomSerializer(s));usingSettings.Expect("renamed").ForField(Field<Precedence>(p => p.RenamedOnConnectionSettings));usingSettings.Expect("nestAtt").ForField(Field<Precedence>(p => p.NestAttribute));usingSettings.Expect("jsonProp").ForField(Field<Precedence>(p => p.JsonProperty));usingSettings.Expect("ask").ForField(Field<Precedence>(p => p.AskSerializer));usingSettings.Expect("DEFAULTFIELDNAMEINFERRER").ForField(Field<Precedence>(p => p.DefaultFieldNameInferrer));
索引文档时也适用相同的命名规则
usingSettings.Expect(new []{ "ask", "DEFAULTFIELDNAMEINFERRER", "jsonProp", "nestAtt", "renamed"}).AsPropertiesOf(new Precedence{ RenamedOnConnectionSettings = "renamed on connection settings", NestAttribute = "using a nest attribute", JsonProperty = "the default serializer resolves json property attributes", AskSerializer = "serializer fiddled with this one", DefaultFieldNameInferrer = "shouting much?"});public class Parent {public int Id { get; set; }public string Description { get; set; }public string IgnoreMe { get; set; } }public class Child : Parent { }
继承的属性可以像预期一样被忽略和重命名
var usingSettings = WithConnectionSettings(s => s .InferMappingFor<Child>(m => m .Rename(p => p.Description, "desc") .Ignore(p => p.IgnoreMe) ));usingSettings.Expect(new []{ "id", "desc",}).AsPropertiesOf(new Child{ Id = 1, Description = "using a nest attribute", IgnoreMe = "the default serializer resolves json property attributes",});
- Elasticsearch(十二)【NEST高级客户端--规范】
- Elasticsearch(五)【NEST高级客户端--开始】
- Elasticsearch(六)【NEST高级客户端--连接】
- Elasticsearch(七)【NEST高级客户端--序列化】
- Elasticsearch(八)【NEST高级客户端--Mapping映射】
- Elasticsearch(九)【NEST高级客户端--分析器】
- Elasticsearch(十)【NEST高级客户端--搜索查询】
- Elasticsearch(十一)【NEST高级客户端--聚合】
- Elasticsearch(十三)【NEST高级客户端--常见类型】
- ElasticSearch NEST
- ElasticSearch NEST搜索
- Elasticsearch .net client NEST使用说明
- Elasticsearch(三)【.Net客户端API规范--生命周期】
- NEST.net Client For Elasticsearch简单应用
- .NET 分布式 搜索 elasticsearch.net NEST
- Elasticsearch NEST使用指南:映射和分析
- .NET 分布式 搜索 elasticsearch.net NEST
- Elasticsearch.Net Nest 5.0.0 用法
- 万众期待的PowerBI Report Server与PowerBI Premium
- 今天,2017第十届省赛结束了
- XDOJ省赛选拔赛第二场H题
- 女生赛hdu6025
- 二分贪心练习题-Y25
- Elasticsearch(十二)【NEST高级客户端--规范】
- macOS系统安装eclipse svn插件及问题解决
- 解决运行ASP.NET MVC项目时,因版本不一致导致无法运行的问题
- android studio 官网下载+安装(win7)
- HDU--2191(多重背包)
- Intersection of Two Arrays
- 129. Sum Root to Leaf Numbers
- [编程之美-11]字符串的全排列问题
- HBCTF——WriteUp&&涨姿势(3)