Elasticsearch .net client NEST使用说明 2.x -更新版

时间:2022-06-12 23:00:08

Elasticsearch .net client NEST使用说明

Elasticsearch.Net、NEST 交流群:523061899

  demo源码 https://github.com/huhangfei/NestDemos

Elasticsearch.Net与NEST是Elasticsearch为C#提供的一套客户端驱动,方便C#调用Elasticsearch服务接口。Elasticsearch.Net是对Elasticsearch服务接口较基层的的实现,NEST是在前者基础之上进行的封装,方法更简洁使用更方便。本文是针对NEST 2.X的使用的总结。

引用

引用dll

NEST.dll
Elasticsearch.Net.dll
Newtonsoft.Json.dll

注:仅支持.net framework>=4.5

概念

 

存储结构:

在Elasticsearch中,文档(Document)归属于一种类型(type),而这些类型存在于索引(index)中.

类比传统关系型数据库:

Relational DB -> Databases -> Tables -> Rows -> Columns
Elasticsearch -> Indices -> Types -> Documents -> Fields

客户端语法

 

链式lambda 表达式( powerful query DSL)语法

s => s.Query(q => q
.Term(p => p.Name, "elasticsearch")
)

对象初始化语法

var searchRequest = new SearchRequest<VendorPriceInfo>
{
Query = new TermQuery
{
Field = "name",
Value = "elasticsearch"
}
};

Connection链接

//单node
Var node = new Uri(“……”);
var settings = new ConnectionSettings(node); //多uris
Var uris = new Uri [] {
new Uri(“……”),
new Uri(“……”)
};
var pool = new StaticConnectionPool(uris); //多node
Var nodes = new Node [] {
new Node (new Uri(“……”)),
new Node (new Uri(“……”))
};
var pool = new StaticConnectionPool(nodes); var settings = new ConnectionSettings(pool); var client = new ElasticClient(settings);

注:nest默认字段名首字母小写,如果要设置为与Model中一致按如下设置。(强烈建议使用该设置)

var settings = new ConnectionSettings(node).DefaultFieldNameInferrer((name) => name);

连接池类型

//单节点
IConnectionPool pool = new SingleNodeConnectionPool(urls.FirstOrDefault()); //请求时随机发送请求到各个正常的节点,不请求异常节点,异常节点恢复后会重新被请求
IConnectionPool pool = new StaticConnectionPool(urls); IConnectionPool pool = new SniffingConnectionPool(urls);
//false.创建客户端时,随机选择一个节点作为客户端的请求对象,该节点异常后不会切换其它节点
//true,请求时随机请求各个正常节点,不请求异常节点,但异常节点恢复后不会重新被请求
pool.SniffedOnStartup = true; //创建客户端时,选择第一个节点作为请求主节点,该节点异常后会切换其它节点,待主节点恢复后会自动切换回来
IConnectionPool pool = new StickyConnectionPool(urls);

索引选择

 

方式1

//链接设置时设置默认使用索引
var settings = new ConnectionSettings().DefaultIndex("defaultindex");

方式2

//链接设置时设置索引与类型对应关系,操作时根据类型使用对应的索引
var settings = new ConnectionSettings().MapDefaultTypeIndices(m => m.Add(typeof(Project), "projects") );

方式3

//执行操作时指定索引
client.Search<VendorPriceInfo>(s => s.Index("test-index"));
client.Index(data,o=>o.Index("test-index"));
 

优先级:方式3 > 方式2 > 方式1

索引(Index)

 

数据唯一Id

1) 默认以“Id”字段值作为索引唯一Id值,无“Id”属性,Es自动生成唯一Id值,添加数据时统一类型数据唯一ID已存在相等值,将只做更新处理。 注:自动生成的ID有22个字符长,URL-safe, Base64-encoded string universally unique identifiers, 或者叫UUIDs。 
2) 标记唯一Id值

[ElasticsearchType(IdProperty = "priceID")]
public class VendorPriceInfo
{
public Int64 priceID { get; set; }
public int oldID { get; set; }
public int source { get; set; }
}

3) 索引时指定

client.Index(data, o => o.Id(data.vendorName));

优先级: 3) > 2) > 1)

类型(Type)

1) 默认类型为索引数据的类名(自动转换为全小写) 2) 标记类型

 [ElasticsearchType(Name = "datatype")]
public class VendorPriceInfo
{
public Int64 priceID { get; set; }
public int oldID { get; set; }
public int source { get; set; }
}

3) 索引时指定

client.Index(data, o => o.Type(new TypeName() { Name = "datatype", Type = typeof(VendorPriceInfo) }));

client.Index(data, o => o.Type<MyClass>());//使用 2)标记的类型

优先级:3)> 2) > 1)

创建

client.CreateIndex("test2");
//基本配置
IIndexState indexState=new IndexState()
{
Settings = new IndexSettings()
{
NumberOfReplicas = ,//副本数
NumberOfShards = //分片数
}
};
client.CreateIndex("test2", p => p.InitializeUsing(indexState)); //创建并Mapping
client.CreateIndex("test-index3", p => p.InitializeUsing(indexState).Mappings(m => m.Map<VendorPriceInfo>(mp => mp.AutoMap())));

注:索引名称必须小写

判断

client.IndexExists("test2");

删除

client.DeleteIndex("test2");

映射

 

概念

每个类型拥有自己的映射(mapping)或者模式定义(schema definition)。一个映射定义了字段类型、每个字段的数据类型、以及字段被Elasticsearch处理的方式。

获取映射

 var resule = client.GetMapping<VendorPriceInfo>();

特性

 /// <summary>
/// VendorPrice 实体
/// </summary>
[ElasticsearchType(IdProperty = "priceID", Name = "VendorPriceInfo")]
public class VendorPriceInfo
{
[Number(NumberType.Long)]
public Int64 priceID { get; set; }
[Date(Format = "mmddyyyy")]
public DateTime modifyTime { get; set; }
/// <summary>
/// 如果string 类型的字段不需要被分析器拆分,要作为一个正体进行查询,需标记此声明,否则索引的值将被分析器拆分
/// </summary>
[String(Index = FieldIndexOption.NotAnalyzed)]
public string pvc_Name { get; set; }
/// <summary>
/// 设置索引时字段的名称
/// </summary>
[String(Name = "PvcDesc")]
public string pvc_Desc { get; set; }
/// <summary>
/// 如需使用坐标点类型需添加坐标点特性,在maping时会自动映射类型
/// </summary>
[GeoPoint(Name = "ZuoBiao",LatLon = true)]
public GeoLocation Location { get; set; }
}

映射

//根据对象类型自动映射
var result= client.Map<VendorPriceInfo>(m => m.AutoMap());
//手动指定
var result1 = client.Map<VendorPriceInfo>(m => m.Properties(p => p
.GeoPoint(gp => gp.Name(n => n.Location)// 坐标点类型
.Fielddata(fd => fd
.Format(GeoPointFielddataFormat.Compressed)//格式 array doc_values compressed disabled
.Precision(new Distance(, DistanceUnit.Meters)) //精确度
))
.String(s => s.Name(n => n.b_id))//string 类型
));
//在原有字段下新增字段(用于存储不同格式的数据,查询使用该字段方法查看【基本搜索】)
//eg:在 vendorName 下添加无需分析器分析的值 temp
var result2 = client.Map<VendorPriceInfo>(
m => m
.Properties(p => p.String(s => s.Name(n => n.vendorName).Fields(fd => fd.String(ss => ss.Name("temp").Index(FieldIndexOption.NotAnalyzed))))));

注:映射时已存在的字段将无法重新映射,只有新加的字段能映射成功。所以最好在首次创建索引后先进性映射再索引数据。 
注:映射时同一索引中,多个类型中如果有相同字段名,那么在索引时可能会出现问题(会使用第一个映射类型)。

数据

 

数据操作

 

说明

  • 添加数据时,如果文档的唯一id在索引里已存在,那么会替换掉原数据;
  • 添加数据时,如果索引不存在,服务会自动创建索引;
  • 如果服务自动创建索引,并索引了数据,那么索引的映射关系就是服务器自动设置的;
  • 通常正确的使用方法是在紧接着创建索引操作之后进行映射关系的操作,以保证索引数据的映射是正确的。然后才是索引数据;
  • 文档在Elasticsearch中是不可变的,执行Update事实上Elasticsearch的处理过程如下:
    • 从旧文档中检索JSON
    • 修改JSON值
    • 删除旧文档
    • 索引新文档

所以我们也可以使用Index来更新已存在文档,只需对应文档的唯一id。

添加索引数据

 

添加单条数据

var data = new VendorPriceInfo() { vendorName = "测试"};
client.Index(data);

添加多条数据

var datas = new List<VendorPriceInfo> {
new VendorPriceInfo(){priceID = ,vendorName = "test1"},
new VendorPriceInfo(){priceID = ,vendorName = "test2"}};
client.IndexMany(datas);

删除数据

 

单条数据

DocumentPath<VendorPriceInfo> deletePath=new DocumentPath<VendorPriceInfo>();
client.Delete(deletePath);

IDeleteRequest request = new DeleteRequest("test3", "vendorpriceinfo", );
client.Delete(request);

注:删除时根据唯一id删除

集合数据

  Indices indices = "test-1";
Types types = "vendorpriceinfo";
//批量删除 需要es安装 delete-by-query插件
var result = client.DeleteByQuery<VendorPriceInfo>(indices, types,
dq =>
dq.Query(
q =>
q.TermRange(tr => tr.Field(fd => fd.priceID).GreaterThanOrEquals("").LessThanOrEquals("")))
);
 

更新数据

 

更新所有字段

DocumentPath<VendorPriceInfo> deletePath=new DocumentPath<VendorPriceInfo>();
Var response=client.Update(deletePath,(p)=>p.Doc(new VendorPriceInfo(){vendorName = "test2update..."}));
//或
IUpdateRequest<VendorPriceInfo, VendorPriceInfo> request = new UpdateRequest<VendorPriceInfo, VendorPriceInfo>(deletePath)
{
Doc = new VendorPriceInfo()
{
priceID = ,
vendorName = "test4update........"
}
};
var response = client.Update<VendorPriceInfo, VendorPriceInfo>(request);
 

更新部分字段

IUpdateRequest<VendorPriceInfo, VendorPriceInfoP> request = new UpdateRequest<VendorPriceInfo, VendorPriceInfoP>(deletePath)
{
Doc = new VendorPriceInfoP()
{
priceID = ,
vendorName = "test4update........"
} };
var response = client.Update(request);
 

更新部分字段

IUpdateRequest<VendorPriceInfo, object> request = new UpdateRequest<VendorPriceInfo, object>(deletePath)
{
Doc = new
{
priceID = ,
vendorName = " test4update........"
}
};
var response = client.Update(request);
//或
client.Update<VendorPriceInfo, object>(deletePath, upt => upt.Doc(new { vendorName = "ptptptptp" }));
 

注:更新时根据唯一id更新

更新时使用本版号加锁机制

 //查询到版本号
var result = client.Search<MessageInfo>(
s =>
s.Index("ep_epdb8buddy_imchatinfo_messageinfo_nopaging_msguid_index").Type("MessageInfo")
.Query(q => q.Term(tm => tm.Field("MsgUID").Value("5DCC-A8C4-44NV-VKGU"))).Size().Version());
foreach (var s in result.Hits)
{
Console.WriteLine(s.Id+" - "+s.Version);
} var path = new DocumentPath<MessageInfo>("5DCC-A8C4-44NV-VKGU");
//更新时带上版本号 如果服务端版本号与传入的版本好相同才能更新成功
var response = client.Update(path, (p) => p.Index("ep_epdb8buddy_imchatinfo_messageinfo_nopaging_msguid_index-2017.03").Type("MessageInfo")
.Version().Doc(new MessageInfo() { MsgUID = "5DCC-A8C4-44NV-VKGU", FromUserName = "测测测" + DateTime.Now }));

获取数据

var response = client.Get(new DocumentPath<VendorPriceInfo>());
//或
var response =
client.Get(new DocumentPath<VendorPriceInfo>(),pd=>pd.Index("test4").Type("v2"));
//多个
var response = client.MultiGet(m => m.GetMany<VendorPriceInfo>(new List<long> { , , , }));

注:获取时根据唯一id获取

批处理操作

var listOps = new List<IBulkOperation>
{
//更新
new BulkUpdateOperation<VendorOfferNewsByCsId, object>(new VendorOfferNewsByCsId() {},
new {Name = "new-project2"}) {Id = ""},
//删除
new BulkDeleteOperation<VendorOfferNewsByCsId>(new Id())
//...
};
IBulkRequest bulkRequest=new BulkRequest("indexname","typename");
var request = new BulkRequest()
{ Operations = listOps
};
client.Bulk(request);

搜索

 

说明

  • 搜索分页时随着分页深入,资源花费是成倍增长的。限制from+size⇐10000分页说明资料 资料
  • 需要扫描所有数据时,使用滚屏扫描。 扫描与滚屏资料
  • 搜索中提供了查询(Query)和过滤(Filter):
  • query是要计算相关性评分的,filter不要;
  • query结果不缓存,filter缓存。
  • 全文搜索、评分排序,使用query;
  • 是非过滤,精确匹配,使用filter。

基本搜索

var result = client.Search<VendorPriceInfo>(
s => s
.Explain() //参数可以提供查询的更多详情。
.FielddataFields(fs => fs //对指定字段进行分析
.Field(p => p.vendorFullName)
.Field(p => p.cbName)
)
.From() //跳过的数据个数
.Size() //返回数据个数
.Query(q =>
q.Term(p => p.vendorID, ) // 主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed的字符串(未经分析的文本数据类型):
&&
q.Term(p => p.vendorName.Suffix("temp"), "姓名") //用于自定义属性的查询 (定义方法查看MappingDemo)
&&
q.Bool( //bool 查询
b => b
.Must(mt => mt //所有分句必须全部匹配,与 AND 相同
.TermRange(p => p.Field(f => f.priceID).GreaterThan("").LessThan(""))) //指定范围查找
.Should(sd => sd //至少有一个分句匹配,与 OR 相同
.Term(p => p.priceID, ),
sd => sd.Terms(t => t.Field(fd => fd.priceID).Terms(new[] {, , })),//多值
//||
//sd.Term(p => p.priceID, 1001)
//||
//sd.Term(p => p.priceID, 1005)
sd => sd.TermRange(tr => tr.GreaterThan("").LessThan("").Field(f => f.vendorPrice))
)
.MustNot(mn => mn//所有分句都必须不匹配,与 NOT 相同
.Term(p => p.priceID, )
,
mn => mn.Bool(
bb=>bb.Must(mt=>mt
.Match(mc=>mc.Field(fd=>fd.carName).Query("至尊"))
))
)
)
)//查询条件
.Sort(st => st.Ascending(asc => asc.vendorPrice))//排序
.Source(sc => sc.Include(ic => ic
.Fields(
fd => fd.vendorName,
fd => fd.vendorID,
fd => fd.priceID,
fd => fd.vendorPrice))) //返回特定的字段
);
//TResult
var result1 = client.Search<VendorPriceInfo, VendorPriceInfoP>(s => s.Query(
q => q.MatchAll()
)
.Size()
);
 

var result = client.Search<VendorPriceInfo>(new SearchRequest()
{
Sort =new List<ISort>
{
new SortField { Field = "vendorPrice", Order = SortOrder.Ascending }
},
Size = ,
From = ,
Query = new TermQuery()
{
Field = "priceID",
Value =
}
||
new TermQuery(
{
Field = "priceID",
Value =
}
});
 

动态拼接条件、排序

 //must 条件
var mustQuerys = new List<Func<QueryContainerDescriptor<VendorOfferNewsByCsId>, QueryContainer>>();
//车型
mustQuerys.Add(mt => mt.Term(tm => tm.Field(fd => fd.csID).Value(csid)));
//should 条件
var shouldQuerys = new List<Func<QueryContainerDescriptor<VendorOfferNewsByCsId>, QueryContainer>>();
//车型
shouldQuerys.Add(mt => mt.Term(tm => tm.Field(fd => fd.csID).Value(csid)));
//排序
Func<SortDescriptor<VendorOfferNewsByCsId>, IPromise<IList<ISort>>> sortDesc = sd =>
{
//根据分值排序
sd.Descending(SortSpecialField.Score); //排序
if (ispc)
sd.Descending(d => d.pDimWeightSort);
else
sd.Descending(d => d.mDimWeightSort);
return sd;
};
var result2 =
client.Search<VendorOfferNewsByCsId>(
s => s
.Index("vendoroffernewsbycsidinfo")
.Type("vendoroffernewsbycsidinfo")
.Query(q => q.Bool(b => b.Must(mustQuerys).Should(shouldQuerys)) )
.Size()
.From()
.Sort(sortDesc)
);

分页

//分页最大限制(from+size<=10000)
int pageSize = ;
int pageIndex = ;
var result = client.Search<VendorPriceInfo>(s => s.Query(q => q
.MatchAll())
.Size(pageSize)
.From((pageIndex - ) * pageSize)
.Sort(st => st.Descending(d => d.priceID)));

扫描和滚屏

string scrollid = "";
var result = client.Search<VendorPriceInfo>(s => s.Query(q => q.MatchAll())
.Size()
.SearchType(SearchType.Scan)
.Scroll("1m"));//scrollid过期时间
//得到滚动扫描的id
scrollid = result.ScrollId;
//执行滚动扫描得到数据 返回数据量是 result.Shards.Successful*size(查询成功的分片数*size)
result = client.Scroll<VendorPriceInfo>("1m", scrollid);
//得到新的id
scrollid = result.ScrollId;

查询条件相关性加权

eg:通过城市与省份查询,设置城市的相关性高于省份的,结果的等分匹配城市的将高于匹配省份的。

// 在原分值基础上 设置不同匹配的加成值 具体算法为lucene内部算法
var result = client.Search<VendorPriceInfo>(s => s
.Query(q =>
q.Term(t => t
.Field(f => f.cityID).Value().Boost())
||
q.Term(t => t
.Field(f => f.pvcId).Value().Boost())
)
.Size()
.Sort(st => st.Descending(SortSpecialField.Score))
);

得分控制

//使用functionscore计算得分
var result1 = client.Search<VendorPriceInfo>(s => s
.Query(q=>q.FunctionScore(f=>f
              //查询区
.Query(qq => qq.Term(t => t
.Field(fd => fd.cityID).Value())
||
qq.Term(t => t
.Field(fd => fd.pvcId).Value())
)
.Boost(1.0) //functionscore 对分值影响
.BoostMode(FunctionBoostMode.Replace)//计算boost 模式 ;Replace为替换
.ScoreMode(FunctionScoreMode.Sum) //计算score 模式;Sum为累加
//逻辑区
.Functions(fun=>fun
.Weight(w => w.Weight().Filter(ft => ft
.Term(t => t
.Field(fd => fd.cityID).Value())))//匹配cityid +2
.Weight(w => w.Weight().Filter(ft => ft
.Term(t => t
.Field(fd => fd.pvcId).Value())))//匹配pvcid +1
)
)
)
.Size()
.Sort(st => st.Descending(SortSpecialField.Score).Descending(dsc=>dsc.priceID))
);
//结果中 cityid=2108,得分=2; pvcid=2103 ,得分=1 ,两者都满足的,得分=3

查询字符串-简单的检索

 var result = client.Search<VendorPriceInfo>(s => s
.Query(q => q.QueryString(m => m.Fields(fd=>fd.Field(fdd=>fdd.carName).Field(fdd=>fdd.carGearBox))
.Query("手自一体")
)
)
.From()
.Size()
);

全文检索-关键词搜索

 var result=client.Search<VendorPriceInfo>(s=>s
.Query(q=>q
.Match(m=>m.Field(f=>f.carName)
.Query("尊贵型")
)
)
.From()
.Size()
);
//多字段匹配
var result1 = client.Search<VendorPriceInfo>(s => s
.Query(q => q
.MultiMatch(m => m.Fields(fd=>fd.Fields(f=>f.carName,f=>f.carGearBox))
.Query("尊贵型")
)
)
.From()
.Size()
);
 

全文搜索-短语搜索

var result = client.Search<VendorPriceInfo>(s => s
.Query(q => q.MatchPhrase(m => m.Field(f => f.carName)
.Query("尊贵型")
)
)
.From()
.Size()
);

坐标点搜索-根据坐标点及距离搜索

eg:搜索指定地点附近所有经销商

const double lat = 39.8694890000;
const double lon = 116.4206470000;
const double distance = 2000.0;
//1 bool查询中作为 must 一个条件
var result = client.Search<VendorPriceInfo>(s => s
.Query(q => q
.Bool(b => b.Must(m => m
.GeoDistance(gd => gd
.Location(lat, lon)
.Distance(distance, DistanceUnit.Meters)
.Field(fd => fd.Location)
))
)
)
.From()
.Size()
);
//2与bool查询同级条件
var location = new GeoLocation(lat, lon);
var distancei = new Distance(distance, DistanceUnit.Meters);
var result1 = client.Search<VendorPriceInfo>(s => s
.Query(q => q
.Bool(b => b.Must(m => m
.Exists(e => e.Field(fd => fd.Location))
)
)
&&
q.GeoDistance(gd => gd
.Location(location)
.Distance(distancei)
.Field(fd => fd.Location)
)
)
.From()
.Size()
);
//3作为bool查询 中must的一个筛选项-筛选项只筛选结果不会影响分值
var result2 = client.Search<VendorPriceInfo>(s => s
.Query(q => q
.Bool(b=>b
.Must(m=>m.MatchAll())
.Filter(f=>f
.GeoDistance(g => g
.Name("named_query")
.Field(p => p.Location)
.DistanceType(GeoDistanceType.Arc)
.Location(lat,lon)
.Distance("2000.0m")
)
)
)
)
.From()
.Size()
);

聚合

 

聚合-基本

var result = client.Search<VendorPriceInfo>(s => s
.From()
.Size()
.Aggregations(ag=>ag
.ValueCount("Count", vc => vc.Field(fd => fd.vendorPrice))//总数
.Sum("vendorPrice_Sum", su => su.Field(fd => fd.vendorPrice))//求和
.Max("vendorPrice_Max", m => m.Field(fd => fd.vendorPrice))//最大值
.Min("vendorPrice_Min", m => m.Field(fd => fd.vendorPrice))//最小值
.Average("vendorPrice_Avg", avg => avg.Field(fd => fd.vendorPrice))//平均值
.Terms("vendorID_group", t => t.Field(fd => fd.vendorID).Size())//分组
)
);
 

聚合-分组

eg:统计每个经销商下的平均报价

 //每个经销商 的平均报价
var result = client.Search<VendorPriceInfo>(s => s
.Size()
.Aggregations(ag => ag
.Terms("vendorID_group", t => t
.Field(fd => fd.vendorID)
.Size()
.Aggregations(agg => agg
//分组后取每组内多少条源数据
.TopHits("top_vendor_hits", th => th.Sort(srt => srt.Field(fd => fd.newsId).Descending()).Size())
.Average("vendorID_Price_Avg", av => av.Field(fd => fd.vendorPrice)))
)//分组
.Cardinality("vendorID_group_count", dy => dy.Field(fd => fd.vendorID))//分组数量
.ValueCount("Count", c => c.Field(fd => fd.vendorID))//总记录数
)
);

聚合-分组-聚合..

eg:统计每个经销商对每个品牌的平均报价、最高报价、最低报价等

//每个经销商下 每个品牌 的平均报价
var result = client.Search<VendorPriceInfo>(s => s
.Size()
.Aggregations(ag => ag
.Terms("vendorID_group", //vendorID 分组
t => t.Field(fd => fd.vendorID)
.Size()
.Aggregations(agg => agg
.Terms("vendorID_cbID_group", //cbID分组
tt => tt.Field(fd => fd.cbID)
.Size()
.Aggregations(aggg => aggg
.Average("vendorID_cbID_Price_Avg", av => av.Field(fd => fd.vendorPrice))//Price avg
.Max("vendorID_cbID_Price_Max", m => m.Field(fd => fd.vendorPrice))//Price max
.Min("vendorID_cbID_Price_Min", m => m.Field(fd => fd.vendorPrice))//Price min
.ValueCount("vendorID_cbID_Count", m => m.Field(fd => fd.cbID))//该经销商对该品牌 报价数 count
)
)
.Cardinality("vendorID_cbID_group_count", dy => dy.Field(fd => fd.cbID))//分组数量
.ValueCount("vendorID_Count", c => c.Field(fd => fd.vendorID))//该经销商的报价数
)
)
.Cardinality("vendorID_group_count",dy=>dy.Field(fd=>fd.vendorID))//分组数量
.ValueCount("Count",c=>c.Field(fd=>fd.priceID))//总记录数
) //分组
);

复杂聚合分组及结果解析

int vendorBizMode = ;
int cId = ;
int csid = ; var mustQuerys = new List<Func<QueryContainerDescriptor<VendorOfferNewsInfo>, QueryContainer>>(); mustQuerys.Add(t => t.Term(f => f.csID, csid));
//mustQuerys.Add(t => t.Term(f => f.cId, cId)); mustQuerys.Add(t => t.Term(f => f.vendorBizMode, vendorBizMode)); var result =
client.Search<VendorOfferNewsInfo>(
s => s.Index("vendoroffernewsinfo").Type("vendoroffernewsinfo")
.Query(q => q
.Bool(b => b.Must(mustQuerys))
)
.Size()
.Sort(st => st.Descending(SortSpecialField.Score).Descending(dsc => dsc.mDimWeightSort))
.Aggregations(ag => ag .Terms("VendorID_Group", tm => tm
.OrderDescending("mDimWeightSort_avg")
.Field(fd => fd.VendorID)
.Size()
.Aggregations(agg => agg
.TopHits("top_vendor_hits", th => th.Sort(srt => srt.Field(fd => fd.newsId).Descending()).Size())
.Max("vendorPrice_Max", m => m.Field(fd => fd.OrderPrice))
.Min("vendorPrice_Min", m => m.Field(fd => fd.OrderPrice))
.Average("mDimWeightSort_avg", avg => avg.Field(fd => fd.mDimWeightSort))
) ) )
);
var vendorIdGroup = (BucketAggregate)result.Aggregations["VendorID_Group"];
var resultInfos = new List<VendorOfferNewsInfo>();
foreach (var bucket1 in vendorIdGroup.Items)
{
var bucket = (KeyedBucket)bucket1; var maxPrice = ((ValueAggregate)bucket.Aggregations["vendorPrice_Max"]).Value;
var minPrice = ((ValueAggregate)bucket.Aggregations["vendorPrice_Min"]).Value;
var sources = ((TopHitsAggregate)bucket.Aggregations["top_vendor_hits"]).Documents<VendorOfferNewsInfo>().ToList();
var data = sources.FirstOrDefault();
data.MaxPrice = (decimal)maxPrice;
data.MinPrice = (decimal)minPrice;
resultInfos.Add(data);
}
var ss = resultInfos;

 

距离单位:

  • mm (毫米)
  • cm (厘米)
  • m (米)
  • km (千米)
  • in (英寸)
  • ft (英尺)
  • yd (码)
  • mi (英里)
  • nmi or NM (海里)

日期单位:

  • y (year)
  • M (month)
  • w (week)
  • d (day)
  • h (hour)
  • m (minute)
  • s (second)
  • ms (milliseconds)

官网文档

Elasticsearch .net client NEST使用说明 2.x -更新版的更多相关文章

  1. Elasticsearch &period;Net Client NEST使用说明 2&period;x

    Elasticsearch .net client NEST使用说明 2.x Elasticsearch.Net与NEST是Elasticsearch为C#提供的一套客户端驱动,方便C#调用Elast ...

  2. (转)Elasticsearch &period;net client NEST使用说明 2&period;x

    Elasticsearch.Net与NEST是Elasticsearch为C#提供的一套客户端驱动,方便C#调用Elasticsearch服务接口.Elasticsearch.Net是较基层的对Ela ...

  3. Elasticsearch &period;net client NEST 5&period;x 使用总结

    目录: Elasticsearch .net client NEST 5.x 使用总结 elasticsearch_.net_client_nest2.x_到_5.x常用方法属性差异 Elastics ...

  4. Elasticsearch &period;Net Client NEST 多条件查询示例

    Elasticsearch .Net Client NEST 多条件查询示例 /// <summary> /// 多条件搜索例子 /// </summary> public c ...

  5. Elasticsearch &period;Net Client NEST 索引DataSet数据

    NEST 索引DataSet数据,先序列化然后转成dynamic 类型进行索引: /// <summary> /// 索引dataset /// </summary> /// ...

  6. Elasticsearch &period;net client NEST 空字符&sol;null值查询

    null值查询 当某个字段值为null时,其实在es里该条数据是没有这个字段的.查询时检测包含不包含该字段就行. /// <summary> /// null 值查询 /// 当数据为Nu ...

  7. elasticsearch系列七:ES Java客户端-Elasticsearch Java client(ES Client 简介、Java REST Client、Java Client、Spring Data Elasticsearch)

    一.ES Client 简介 1. ES是一个服务,采用C/S结构 2. 回顾 ES的架构 3. ES支持的客户端连接方式 3.1 REST API ,端口 9200 这种连接方式对应于架构图中的RE ...

  8. Elasticsearch Java Client连接池

    按照Elasticsearch API,在Java端使用是ES服务需要创建Java Client,但是每一次连接都实例化一个client,对系统的消耗很大,即使在使用完毕之后将client close ...

  9. Elasticsearch Java client(ES Client 简介、Java REST Client、Java Client、Spring Data Elasticsearch)

    elasticsearch系列七:ES Java客户端-Elasticsearch Java client(ES Client 简介.Java REST Client.Java Client.Spri ...

随机推荐

  1. CYQ&period;Data V5 从入门到放弃ORM系列:教程 - MProc类使用

    MProc介绍 MProc:是一个用于执行SQL或存储过程的数据库操作类,它轻量高性能地类似于Dapper. MProc:它出现的场景很少,因为MAction自身就能处理掉90%-100%的数据操作( ...

  2. C&num;利用SqlDataAdapte对DataTable进行批量数据操作

    C#利用SqlDataAdapte对DataTable进行批量数据操作,可以让我们大大简化操作数据的代码量,我们几乎不需要循环和不关心用户到底是新增还是修改,更不用编写新增和修改以及删除的SQL语句, ...

  3. 洛谷P2327 &lbrack;SCOI2005&rsqb; 扫雷

    题目描述 输入输出格式 输入格式: 第一行为N,第二行有N个数,依次为第二列的格子中的数.(1<= N <= 10000) 输出格式: 一个数,即第一列中雷的摆放方案数. 输入输出样例 输 ...

  4. Regular expression cheat sheet

    \s white-space characters \S Non-white-space characters \d digital numbers \D non-digital numbers \w ...

  5. 航道水下地形DEM构建方法比较

    论文<航道水下数字高程模型的构建方法> 对航道水下地形建立DEM,技术路线:先构建TIN,手动去除多余三角边,再利用CAD ObjectARX二次开发接口中提供的几种内插方法生成grid ...

  6. jQuery 表格

    jQuery 表格插件汇总     本文搜集了大量 jQuery 表格插件,帮助 Web 设计者更好地驾御 HTML 表格,你可以对表格进行横向和竖向排序,设置固定表头,对表格进行搜索,对大表格进行分 ...

  7. script —— 终端里的记录器

    当 你在终端或者控制台工作时,你可能想要记录在终端中所做的一切.这些记录可以用来当作史料,保存终端所发生的一切.比如说,你和一些Linux管理员们同 时管理着相同的机器,或者你让某人远程登陆到了你的服 ...

  8. FPGA上如何求32个输入的最大值和次大值:分治

    上午在论坛看到个热帖,里头的题目挺有意思的,简单的记录了一下. 0. 题目 在FPGA上实现一个模块,求32个输入中的最大值和次大值,32个输入由一个时钟周期给出.(题目来自论坛,面试题,如果觉得不合 ...

  9. &period;NET&sol;C&num; 反射的的性能数据,以及高性能开发建议(反射获取 Attribute 和反射调用方法)——转载

    原文链接:https://blog.walterlv.com/post/dotnet-high-performance-reflection-suggestions.html ***** 大家都说反射 ...

  10. Memcached在Windows下的配置和使用

    Memcached学习笔记---- 安装和配置 首先,下载Memcached相关文件. 打开控制台,进入Memcached主程序目录,输入: memcached.exe -d install //安装 ...