本文中,数据(文档)之间的关系类型,是嵌套文档
1、安装:
elasticsearch-5.6.2
2、引用:
Elasticsearch.Net(这里使用的是6.0.0)
Nest(这里使用的是6.0.0)
public class ESProvider
{
public ElasticClient ESClient;
public ESProvider()
{
try
{
//单个节点
//var node = new Uri(ElasticSearchSetting.ServerNode);
//ConnectionSettings settings = new ConnectionSettings(node);
//settings.RequestTimeout(TimeSpan.FromSeconds(ElasticSearchSetting.RequestTimeout));//超时时间
//settings.DefaultIndex(ElasticSearchSetting.DefaultIndexName.ToLower());//默认索引(可选,索引名必须小写)
//ESClient = new ElasticClient(settings);
//多节点(方便扩展)
string server = ElasticSearchSetting.ServerNode;
string[] serverArray = server.Split(',');
Uri[] nodesArray = new Uri[serverArray.Length];
for (int i = 0; i < serverArray.Length; i++)
{
nodesArray[i] = new Uri(serverArray[i]);
}
//var connectionPool = new SniffingConnectionPool(nodesArray);
var connectionPool = new StaticConnectionPool(nodesArray);
var settings = new ConnectionSettings(connectionPool);
settings.RequestTimeout(TimeSpan.FromSeconds(ElasticSearchSetting.RequestTimeout));//超时时间
settings.DefaultIndex(ElasticSearchSetting.DefaultIndexName.ToLower());//默认索引(可选,索引名必须小写)
ESClient = new ElasticClient(settings);
}
catch (Exception ex)
{
}
}
}
配置文件:
//IdProperty指定主键
[ElasticsearchType(Name = "ES_GoodsSpu", IdProperty = "GoodsSpuId")]
public class ES_GoodsSpu
{
[Keyword(Index = true)]
public string GoodsSpuId { get; set; }
[Text(Index = true, Analyzer = "ik_max_word")]
public string GoodsName { get; set; }
[Keyword(Index = false)]
public string GoodsMainImg { get; set; }
[Text(Index = true, Analyzer = "ik_max_word")]
public string GoodsContent { get; set; }
[Text(Index = true, Analyzer = "ik_max_word")]
public string GoodsLabel { get; set; }
[Keyword(Index = true)]
public string AddTime { get; set; }
[Nested]
public List GoodsSkuList { get; set; }
}
public class ES_GoodsSku
{
[Keyword(Index = true)]
public string GoodsSpuId { get; set; }
[Keyword(Index = true)]
public string GoodsSkuId { get; set; }
[Keyword(Index = true)]
public string SkuName { get; set; }
[Number(NumberType.Double, Index = false)]
public double SkuWidth { get; set; }
[Number(NumberType.Double, Index = false)]
public double SkuLength { get; set; }
[Number(NumberType.Double, Index = false)]
public double SkuHeight { get; set; }
[Number(NumberType.Byte, Index = true)]
public byte SkuColor { get; set; }
//Elasticsearch中没有decimal等效的类型,最近的类型是double
[Number(NumberType.Double, Index = true)]
public decimal SkuPrice { get; set; }
[Keyword(Index = false)]
public DateTime AddTime { get; set; }
}
public bool CreateIndex(string indexName)
{
try
{
if (string.IsNullOrWhiteSpace(indexName))
return false;
indexName = indexName.ToLower();
IndexState indexState = new IndexState
{
Settings = new IndexSettings
{
NumberOfReplicas = 1, //副本数
NumberOfShards = 5 //分片数
}
};
ICreateIndexResponse response = ESClient.CreateIndex(indexName, p => p
//.InitializeUsing(indexState)//默认即可
.Mappings(m => m.Map(mp => mp.AutoMap()))//自动映射
);
return response.IsValid;
}
catch (Exception ex)
{
return false;
}
}
public bool Add(ES_GoodsSku model,string indexName)
{
try
{
if (model == null)
return false;
var response = ESClient.Index(model, x => x.Index(indexName));
return response.IsValid;
}
catch (Exception ex)
{
return false;
}
}
///
/// 单个删除
///
///
///
public bool DeleteBySpuId(string spuId)
{
try
{
if (string.IsNullOrWhiteSpace(spuId))
return false;
var response = ESClient.DeleteByQuery(
i => i
.Index(indexName)
.Query(q => q.Term(t => t.Field(f => f.GoodsSpuId).Value(spuId)))
);
return response.IsValid;
}
catch (Exception ex)
{
return false;
}
}
///
/// 批量删除
///
///
///
public bool DeleteBySpuIdArray(string[] spuIdArray)
{
try
{
if (spuIdArray.Length <= 0)
return false;
var response = ESClient.DeleteByQuery(
i => i
.Index(indexName)
.Query(q => q.Terms(t => t.Field(f => f.GoodsSpuId).Terms(spuIdArray)))
);
return response.IsValid;
}
catch (Exception ex)
{
return false;
}
}
1、简单查询(包括嵌套查询)
///
/// 查询
///
/// 参数
/// 数量
/// 排序
///
public List GetList(Dictionary param, int num, string orderby = null)
{
try
{
//排序
Func, IPromise>> sortDesc = sd =>
{
//根据分值排序
sd.Ascending(SortSpecialField.Score);
sd.Ascending(d => d.AddTime);
return sd;
};
//must 条件
var mustQuerys = new List, QueryContainer>>();
//must not 条件
var mustNotQuerys = new List, QueryContainer>>();
//should 条件
var shouldQuerys = new List, QueryContainer>>();
if (param != null && param.Count > 0)
{
foreach (KeyValuePair kvp in param)
{
if (string.IsNullOrWhiteSpace(kvp.Value.ToString()))
continue;
string key = kvp.Key.ToLower();
string value = kvp.Value.ToString();
switch (key)
{
case "spuids": //多个id集合
if (!string.IsNullOrWhiteSpace(value) && value.Split(',').Count() > 0)
{
string[] spuIdArray = value.Split(',');
mustQuerys.Add(mq => mq.Terms(tm => tm.Field(f => f.GoodsSpuId).Terms(spuIdArray)));
}
break;
case "name":
mustQuerys.Add(mq => mq.Term(tm => tm.Field(f => f.GoodsName).Value(value)));
break;
case "color":
byte color = 0;
byte.TryParse(value, out color);
if (color > 0)
{
//嵌套查询(Nested,Path)
mustQuerys.Add(mq => mq.Nested(n => n.Path(p => p.GoodsSkuList).Query(q => q.Term(tm => tm.Field(f => f.GoodsSkuList.FirstOrDefault().SkuColor).Value(color)))));
}
break;
case "minprice":
double minprice = -1;//默认值
double.TryParse(value, out minprice);
if (minprice > -1)
{
double maxprice0 = 9999999999;//需要和LessThanOrEquals一起才起作用,所以这里给个最大值
//嵌套查询(Nested,Path)
mustQuerys.Add(mq => mq.Nested(n => n.Path(p => p.GoodsSkuList).Query(q => q.Range(tm => tm.Field(f => f.GoodsSkuList.FirstOrDefault().SkuPrice).GreaterThanOrEquals(minprice).LessThanOrEquals(maxprice0)))));
}
break;
case "maxprice":
double maxprice = -1;//默认值
double.TryParse(value, out maxprice);
if (maxprice > -1)
{
//嵌套查询(Nested,Path)
mustQuerys.Add(mq => mq.Nested(n => n.Path(p => p.GoodsSkuList).Query(q => q.Range(tm => tm.Field(f => f.GoodsSkuList.FirstOrDefault().SkuPrice).LessThanOrEquals(maxprice)))));
}
break;
}
}
}
//搜索
var searchResults = base.ESClient.Search(s => s
.Index(indexName)
.Size(num)
.Query(q => q.Bool(b => b.Must(mustQuerys).MustNot(mustNotQuerys).Should(shouldQuerys)))
.Sort(sortDesc)
);
return searchResults.Documents.ToList();
}
catch (Exception ex)
{
LogObj.GetLogService().LogDetailError(ex);
return null;
}
}
2、分页查询
///
/// 分页查询
///
/// 页索引
/// 页大小
/// 参数
/// 总数量
/// 总页数
/// 排序
///
public List GetPageList(int pageIndex, int pageSize, Dictionary param, ref long totalCount, ref long totalPage, string orderby = null)
{
try
{
//排序
Func, IPromise>> sortDesc = sd =>
{
//根据分值排序
sd.Descending(SortSpecialField.Score);
sd.Descending(d => d.AddTime);
return sd;
};
//must 条件
var mustQuerys = new List, QueryContainer>>();
//should 条件
var shouldQuerys = new List, QueryContainer>>();
if (param != null && param.Count > 0)
{
foreach (KeyValuePair kvp in param)
{
if (string.IsNullOrWhiteSpace(kvp.Value.ToString()))
continue;
string key = kvp.Key.ToLower();
string value = kvp.Value.ToString();
switch (key)
{
case "name":
mustQuerys.Add(mq => mq.Term(tm => tm.Field(f => f.GoodsName).Value(value)));
break;
case "querykey":
//should条件
shouldQuerys.Add(mq => mq.Term(tm => tm.Field(f => f.GoodsName).Value(value)));
shouldQuerys.Add(mq => mq.Term(tm => tm.Field(f => f.GoodsLabel).Value(value)));
shouldQuerys.Add(mq => mq.Term(tm => tm.Field(f => f.GoodsContent).Value(value)));
break;
}
}
}
//搜索
var searchResults = base.ESClient.Search(s => s
.Index(indexName)
.From(pageSize * (pageIndex - 1))
.Size(pageSize)
.Query(q => q.Bool(b => b.Must(mustQuerys).Should(shouldQuerys)))
.Sort(sortDesc)
);//匹配全部
//总数、总页数
totalCount = searchResults.Total;
totalPage = (long)Math.Ceiling((double)totalCount / (double)pageSize);
//返回
return searchResults.Documents.ToList();
}
catch (Exception ex)
{
return null;
}
}
3、分组查询(根据品牌id,获取每个品牌下商品数量)
///
/// 根据品牌id分组,统计每个品牌下的商品数量
///
///
public List> GetGroupByBrandId(List brnadIdList)
{
try
{
if (brnadIdList.Count <= 0)
return null;
string groupName = "BrandID_group";
var result = base.ESClient.Search(s => s
.Index(indexName)
.Query(q => q.Terms(tm => tm.Field(f => f.BrandID).Terms(brnadIdList.ToArray())))
.Aggregations(ag => ag
.Terms(groupName, t => t
.Field("brandID.keyword") //分组字段需要为keyword类型,所以这里加了".keyword"后缀,并且brandID名称要和es相同(包括大小写)
.Size(brnadIdList.Count) //分组数(这里和品牌id集合数相同)
)
)
);
if (result.IsValid)
{
List> tupleList = new List>();
var vendorIdGroup = (BucketAggregate)result.Aggregations[groupName];
foreach (var bucket in vendorIdGroup.Items)
{
var obj = (KeyedBucket
上面代码中Field("brandID.keyword"),如果字段不是keyword类型,会报exception [type=search_phase_execution_exception, reason=all shards failed]错误。
最后:
这里只是把我的项目中代码简单复制了过来,也是第一次使用ElasticSearch,各种查资料,终于不负有心人,功能最终都实现了,如果有错误或者有改进之处,望不吝赐教。