模型类:
public class Computer
{
public int Id { get; set; }
public string Name { get; set; }
public string OtherInfo { get; set;}
}
插入数据:
数据太多,插入时可能有些不成功,多试几次就好了。但我也不知道原因是什么。
索引要全为小写
var nodes = "http://192.168.50.233:9200/".Split(';').Select(t => new Uri(t));
var pool = new StaticConnectionPool(nodes);
var connectionSettings = new ConnectionSettings(pool);
var es = new ElasticClient(connectionSettings);
Computer cp1 = new Computer { Id = 5, Name = "神州笔记本1", OtherInfo = "5" };
Computer cp2 = new Computer { Id = 2, Name = "联想笔记本1", OtherInfo = "2" };
Computer cp3 = new Computer { Id = 3, Name = "戴尔笔记本1", OtherInfo = "3" };
Computer cp4 = new Computer { Id = 4, Name = "惠普笔记本1", OtherInfo = "4" };
List<Computer> cps = new List<Computer> { cp1, cp2, cp3, cp4 };
//http://192.168.50.233:9200/realyuseit/computer/_search?typed_keys=true
Result result = Result.NotFound;
int n = 0;
cps.ForEach(cp =>
{
result = es.Index(cp, t =>
t.Index("realyuseit")
.Type(TypeName.Create<Computer>())
.Id(cp.Id)
).Result;
if (result == Result.Created || result == Result.Updated) n++;
});
Console.WriteLine(n);
查询:
var nodes = "http://192.168.50.233:9200/".Split(';').Select(t => new Uri(t));
var pool = new StaticConnectionPool(nodes);
var connectionSettings = new ConnectionSettings(pool);
var es = new ElasticClient(connectionSettings);
bool eb = es.IndexExists("realyuseit").Exists;
var result = es.Search<Computer>(x =>
x.Index("realyuseit")
//.Query(q => q.Match(m => m.Field(f => f.Name).Query("其他笔记本6"))) //单字段全文关键字检索 只要Name中包含值即可,且自带分词 4条数据符合
//.Query(q => q.MultiMatch(m => m.Fields(fd=>fd.Fields(f=>f.Name,f=>f.OtherInfo)).Query("1神23456789"))) //多字段全文关键字检索 Name或OtherInfo包含该值即可,且自带分词 4条数据符合
//.Analyzer("") // 该分词方法可不需要,因为上面的查询自带分词
//.Query(q => q.Bool(b=>b.Must(m=>m.Term(p=>p.Field(f=>f.Id).Value(4))))) //条件必须符合,无分词,有一些数据类型可能查询失败
//.Query(q => q.Range(c => c.Field(f => f.Id).LessThanOrEquals(5).GreaterThanOrEquals(3))) //范围查询
.Sort(t => t.Ascending(p=>p.Id)) //id升序
//.From(0) //分页
//.Size(3)
);
//以第二次为准,es的特点大家也都知道,我一个小菜鸟还不知道怎么解决,不过查2次够我用了
if (result.Documents.Count == 0)
{
result = es.Search<Computer>(x =>
x.Index("realyuseit")
//.Query(q => q.Match(m => m.Field(f=>f.Name).Query("其他笔记5本6"))) //单字段全文关键字检索 只要Name中包含该值即可,且自带分词
//.Query(q => q.MultiMatch(m => m.Fields(fd => fd.Fields(f => f.Name, f => f.OtherInfo)).Query("1神23456789"))) //多字段全文关键字检索 Name或OtherInfo包含该值即可,且自带分词
//.Analyzer("") // 该分词方法可不需要,因为上面的查询自带分词
//.Query(q => q.Bool(b => b.Must(m => m.Term(p => p.Field(f => f.Id).Value(4))))) //条件必须符合的查询,无分词,有一些数据类型可能查询失败
//.Query(q=>q.Range(c=>c.Field(f=>f.Id).LessThanOrEquals(5).GreaterThanOrEquals(3))) //范围查询
.Sort(t => t.Ascending(p => p.Id))
//.From(0) //分页
//.Size(3)
);
//多个条件一起搜索,例子如下
//var matchQuery = new List<Func<QueryContainerDescriptor<Computer>, QueryContainer>>
//{
// must => must.Bool(b => b.Must(m => m.Term(p => p.Field(f => f.Id).Value(5)),
// m => m.Term(p => p.Field(f => f.Name).Value("神州笔记本1"))
// )
// ),
// range => range.Range(c => c.Field(p => p.Id).LessThanOrEquals(5).GreaterThanOrEquals(3))
//};
//var tr = es.Search<Computer>(x=>x.Index("realyuseit").Query(q=>q.Bool(b=>b.Must(matchQuery))));
}
var res = result.Documents.ToList();
var rb = true;
删除数据
偶尔会出现删除不成功的情况,多试几次就好了,但原因是什么我也不知道。
//删除指定/index/type/id数据
//var result = es.Delete(new DeleteRequest("realyuseit",TypeName.Create<Computer>(),5)).Result;
删除索引
好像还没成功过。
var resultindex = es.DeleteIndex("realyuseit");
不过可以通过发起一个 Delete 方式的http请求将索引直接删除
再次查询就会发现索引不存在了,里面的数据也不存在了。
string indexurl = "http://192.168.50.233:9200/realyuseit";
var request = WebRequest.Create(indexurl);
request.Method = "Delete";
string s = "";
try
{
s = new StreamReader(request.GetResponse().GetResponseStream()).ReadToEnd();
}
catch {
Console.WriteLine("ok");
return;
}
DeleteIndexResult res = JsonConvert.DeserializeObject<DeleteIndexResult>(s);
if (res.acknowledged)
{
Console.WriteLine("ok");
}
else {
if (res.status == 404)
{
Console.WriteLine("ok");
}
else {
Console.WriteLine("false");
}
}
封装Nest:6.5.1框架辅助类
/// <summary>
/// nuget包: nest:6.5.1
/// </summary>
public class ElasticSearchHelper
{
private readonly ElasticClient _Es;
//以下划线 _ 结尾
private readonly string KeyPrefix = string.Empty;
//以斜杆 / 结尾
private readonly string FirstConnectUri = string.Empty;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="connection">需以 / 结尾</param>
/// <param name="prifeix">默认为空</param>
/// <param name="version">默认为0</param>
/// 例如:var es = new ElasticSearchHelper("http://192.168.50.233:9200/");
public ElasticSearchHelper(string connection, string prifeix = "", int version = 0)
{
var uris = connection.Split(';').Select(t => new Uri(t));
var pool = new StaticConnectionPool(uris);
var connectionSettings = new ConnectionSettings(pool);
_Es = new ElasticClient(connectionSettings);
FirstConnectUri = uris.First().AbsoluteUri;
if (!string.IsNullOrWhiteSpace(prifeix) && !prifeix.Equals("test", StringComparison.CurrentCultureIgnoreCase) && version > 0)
{
KeyPrefix = (prifeix + "_" + version + "_").ToLower();
}
}
/// <summary>
/// 添加或修改Es数据
/// </summary>
/// <param name="key">键值</param>
/// <typeparam name="T">数据类型</typeparam>
/// <param name="id">主键</param>
/// <param name="data">数据</param>
/// <returns>结果</returns>
public bool AddOrUpdateEs<T>(string key, long id, T data) where T : class
{
//索引小写
string Key = (KeyPrefix + key).ToLower();
Result result = _Es.Index(data, t => t.Index(Key).Type(TypeName.Create<T>()).Id(id)).Result;
if (result == Result.Created || result == Result.Updated)
{
return true;
}
else
{
result = _Es.Index(data, t => t.Index(Key).Type(TypeName.Create<T>()).Id(id)).Result;
return result == Result.Created || result == Result.Updated;
}
}
/// <summary>
/// 根据分好词的词语用短语匹配搜索,用这种第三方分词加短语匹配的用法替代没有ik分词的Es环境。
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key">索引</param>
/// <param name="phrases">已经分好的词语</param>
/// <param name="fieldName">对指定字段搜索,字段名使用nameof()获取</param>
public List<T> PhraseSearch<T>(string key, string fieldName, string[] phrases) where T : class
{
//索引小写
string Key = (KeyPrefix + key).ToLower();
List<Func<QueryContainerDescriptor<T>, QueryContainer>> shoulds = new List<Func<QueryContainerDescriptor<T>, QueryContainer>>();
foreach (string p in phrases)
{
shoulds.Add(a => a.MatchPhrase(m => m.Field(fieldName.First().ToString().ToLower() + fieldName.Substring(1)).Query(p)));
}
var res = _Es.Search<T>(x => x.Index(Key).Query(a => a.Bool(b => b.Should(shoulds)))).Documents.ToList();
if (res.Count == 0)
{
res = _Es.Search<T>(x => x.Index(Key).Query(a => a.Bool(b => b.Should(shoulds)))).Documents.ToList();
}
return res;
}
/// <summary>
/// 用这种第三方分词加短语匹配的用法替代没有ik分词的Es环境。
/// 第三方分词采用 nuget包:JIEba.Lucene.Net:1.0.16
/// github:https://github.com/SilentCC/JIEba-netcore2.0
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="fieldName"></param>
/// <param name="str"></param>
/// <returns></returns>
public List<T> PhraseSearchByJieBa<T>(string key, string fieldName, string str) where T : class
{
var segmenter = new JiebaSegmenter();
string[] phrases = segmenter.CutForSearch(str).ToArray();
//索引小写
string Key = (KeyPrefix + key).ToLower();
List<Func<QueryContainerDescriptor<T>, QueryContainer>> shoulds = new List<Func<QueryContainerDescriptor<T>, QueryContainer>>();
foreach (string p in phrases)
{
shoulds.Add(a => a.MatchPhrase(m => m.Field(fieldName.First().ToString().ToLower() + fieldName.Substring(1)).Query(p)));
}
var res = _Es.Search<T>(x => x.Index(Key).Query(a => a.Bool(b => b.Should(shoulds)))).Documents.ToList();
if (res.Count == 0)
{
res = _Es.Search<T>(x => x.Index(Key).Query(a => a.Bool(b => b.Should(shoulds)))).Documents.ToList();
}
return res;
}
/// <summary>
/// 删除指定Id的Es数据
/// </summary>
/// <typeparam name="T">数据类型</typeparam>
/// <param name="key">键值</param>
/// <param name="id">主键</param>
/// <returns></returns>
public bool DeleteEs<T>(string key, long id) where T : class
{
//索引小写
string Key = (KeyPrefix + key).ToLower();
var result = _Es.Delete(new DeleteRequest(Key, TypeName.Create<T>(), id)).Result;
if (result == Result.Deleted || result == Result.NotFound)
{
return true;
}
else
{
result = _Es.Delete(new DeleteRequest(Key, TypeName.Create<T>(), id)).Result;
return result == Result.Deleted || result == Result.NotFound;
}
}
/// <summary>
/// 删除索引的所有的数据,http方式,支持模糊匹配索引。
/// 例如:以user开头的有user1,user2,则传入key值为user*
/// </summary>
/// <param name="key">索引</param>
/// <returns></returns>
public bool DeleteIndexHttp(string key)
{
try
{
//索引小写
string Key = key.ToLower();
var request = WebRequest.Create(FirstConnectUri + Key);
request.Method = "Delete";
string s = new StreamReader(request.GetResponse().GetResponseStream()).ReadToEnd();
IndexResult res = JsonObject.Json2Object<IndexResult>(s);
if (res.acknowledged)
{
return true;
}
else
{
if (res.status == 404)
{
return true;
}
else
{
return false;
}
}
}
catch (Exception ex)
{
return true;
}
}
/// <summary>
/// 删除Es索引,且删除索引对应的所有数据
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public bool DeleteIndex(string key)
{
//索引小写
string Key = (KeyPrefix + key).ToLower();
if (!_Es.IndexExists(Key).Exists)
{
return true;
}
var result = _Es.DeleteIndex(Key).Acknowledged;
if (!result)
{
result = _Es.DeleteIndex(Key).Acknowledged;
}
return result;
}
/// <summary>
/// 分页检索Es数据(同步)
/// </summary>
/// <typeparam name="T">数据类型</typeparam>
/// <param name="key">键值</param>
/// <param name="lastRow">跳过的数据个数</param>
/// <param name="takeCnt">返回数据个数</param>
/// <param name="matchQuery">例子如下:
/// var matchQuery = new List<Func<QueryContainerDescriptor<Computer>, QueryContainer>>
/// {
/// must => must.Bool(b => b.Must(m => m.Term(p => p.Field(f => f.Filed).Value(value)))),//条件必须符合的查询,无分词,有一些数据类型可能查询失败
/// range => range.Range(c => c.Field(p => p.Id).LessThanOrEquals(5).GreaterThanOrEquals(3)),//范围查询
/// match => match.Match(m => m.Field(f=>f.Name).Query("string(自动分词)")), //单字段全文关键字检索 只要Name中包含该值即可,且自带分词
/// multimatch => multimatch.MultiMatch(m => m.Fields(fd => fd.Fields(f => f.Name, f => f.OtherInfo)).Query("string(自动分词)")) //多字段全文关键字检索 Name或OtherInfo包含该值即可,且自带分词
/// };
/// </param>
/// <param name="sort">new Func<SortDescriptor<ResFacechatTableInfo>, IPromise<IList<ISort>>>(p => p.Descending(o => o.Field));o为模型类,Field为指定的排序属性名</param>
/// <param name="analyzer">分词器(ik_smart:最粗粒度的拆分,ik_max_word:最细粒度的拆分)</param>
/// <returns></returns>
public List<T> SearchEs<T>(string key, int lastRow = 0, int takeCnt = 100,
List<Func<QueryContainerDescriptor<T>, QueryContainer>> matchQuery = null,
Func<SortDescriptor<T>, IPromise<IList<ISort>>> sort = null) where T : class
{
//索引小写
string Key = (KeyPrefix + key).ToLower();
var result = matchQuery != null ?
_Es.Search<T>(x => x
.Index(Key)
.Query(q => q.Bool(b => b.Must(matchQuery)))
.From(lastRow)
.Size(takeCnt)
.Sort(sort)) :
_Es.Search<T>(x => x
.Index(Key)
.From(lastRow)
.Size(takeCnt)
.Sort(sort))
;
if (result.Documents.Count == 0)
{
result = matchQuery != null ?
_Es.Search<T>(x => x
.Index(Key)
.Query(q => q.Bool(b => b.Must(matchQuery)))
.From(lastRow)
.Size(takeCnt)
.Sort(sort)) :
_Es.Search<T>(x => x
.Index(Key)
.From(lastRow)
.Size(takeCnt)
.Sort(sort));
}
return result.Documents.ToList();
}
/// <summary>
/// 分页检索Es数据(异步)
/// </summary>
/// <typeparam name="T">数据类型</typeparam>
/// <param name="key">键值</param>
/// <param name="lastRow">跳过的数据个数</param>
/// <param name="takeCnt">返回数据个数</param>
/// <param name="matchQuery">例子如下:
/// var matchQuery = new List<Func<QueryContainerDescriptor<Computer>, QueryContainer>>
/// {
/// must => must.Bool(b => b.Must(m => m.Term(p => p.Field(f => f.Filed).Value(value)))),//条件必须符合的查询,无分词,有一些数据类型可能查询失败
/// range => range.Range(c => c.Field(p => p.Id).LessThanOrEquals(5).GreaterThanOrEquals(3)),//范围查询
/// match => match.Match(m => m.Field(f=>f.Name).Query("string(自动分词)")), //单字段全文关键字检索 只要Name中包含该值即可,且自带分词
/// multimatch => multimatch.MultiMatch(m => m.Fields(fd => fd.Fields(f => f.Name, f => f.OtherInfo)).Query("string(自动分词)")) //多字段全文关键字检索 Name或OtherInfo包含该值即可,且自带分词
/// };
/// </param>
/// <param name="sort">new Func<SortDescriptor<ResFacechatTableInfo>, IPromise<IList<ISort>>>(p => p.Descending(o => o.Field));o为模型类,Field为指定的排序属性名</param>
/// <param name="analyzer">分词器(ik_smart:最粗粒度的拆分,ik_max_word:最细粒度的拆分)</param>
/// <returns></returns>
public async Task<List<T>> SearchEsAsync<T>(string key, int lastRow = 0, int takeCnt = 100,
List<Func<QueryContainerDescriptor<T>, QueryContainer>> matchQuery = null,
Func<SortDescriptor<T>, IPromise<IList<ISort>>> sort = null) where T : class
{
//索引小写
string Key = (KeyPrefix + key).ToLower();
var result = matchQuery != null ?
await _Es.SearchAsync<T>(x => x
.Index(Key)
.Query(q => q.Bool(b => b.Must(matchQuery)))
.From(lastRow)
.Size(takeCnt)
.Sort(sort)) :
await _Es.SearchAsync<T>(x => x
.Index(Key)
.From(lastRow)
.Size(takeCnt)
.Sort(sort))
;
if (result.Documents.Count == 0)
{
result = matchQuery != null ?
await _Es.SearchAsync<T>(x => x
.Index(Key)
.Query(q => q.Bool(b => b.Must(matchQuery)))
.From(lastRow)
.Size(takeCnt)
.Sort(sort)) :
await _Es.SearchAsync<T>(x => x
.Index(Key)
.From(lastRow)
.Size(takeCnt)
.Sort(sort));
}
return result.Documents.ToList();
}
/// <summary>
/// 自定义复杂查询
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="func"></param>
/// <returns></returns>
public List<T> SearchFunc<T>(Func<ElasticClient, List<T>> func)
{
var result = func(_Es);
if (result.Count == 0)
{
return func(_Es);
}
return result;
}
/// <summary>
/// 自定义操作_Es
/// </summary>
/// <param name="func"></param>
public void Func(Action<ElasticClient> func)
{
func(_Es);
}
/// <summary>
/// 给指定的index/type设置对应字段的分词器
/// </summary>
/// <param name="key"></param>
/// <param name="typename">type名称,全小写</param>
/// <param name="analyzer">分词器名称</param>
/// <param name="filedsname">字段名,使用nameof()获取</param>
/// <returns></returns>
public bool SetAnalyzer(string key, string typename, string analyzer = null, params string[] filedsname)
{
if (string.IsNullOrWhiteSpace(analyzer) || filedsname.Length == 0)
{
//默认分词
return true;
}
//type全小写
typename = typename.ToLower();
//filed首字母小写
filedsname = filedsname.Select(p => p.First().ToString().ToLower() + p.Substring(1)).ToArray();
//索引小写
string Key = (KeyPrefix + key).ToLower();
//创建索引
bool resb = _Es.CreateIndex(Key).Acknowledged == false ? _Es.CreateIndex(Key).Acknowledged : true;
//映射
string mappingstringStart = "{\"properties\":{";
string mappingstringEnd = "}}";
for (int i = 0; i < filedsname.Length; i++)
{
string item = string.Empty;
if (i == 0)
{
item = "\"" + filedsname[i] + "\":{\"type\":\"string\",\"analyzer\":\"" + analyzer + "\"}";
}
else
{
item = ",\"" + filedsname[i] + "\":{\"type\":\"string\",\"analyzer\":\"" + analyzer + "\"}";
}
mappingstringStart += item;
}
mappingstringStart += mappingstringEnd;
try
{
var request = WebRequest.Create(FirstConnectUri + Key + "/_mapping/" + typename);
request.Method = "put";
Stream requestStream = request.GetRequestStream();
requestStream.Write(Encoding.UTF8.GetBytes(mappingstringStart));
requestStream.Close();
string s = new StreamReader(request.GetResponse().GetResponseStream()).ReadToEnd();
IndexResult res = JsonObject.Json2Object<IndexResult>(s);
if (res.acknowledged)
{
return true;
}
return false;
}
catch (Exception ex)
{
return false;
}
}
private class IndexResult
{
/// <summary>
/// 为true,代表删除Index成功。为false,代表删除失败,不正常。默认false
/// </summary>
public bool acknowledged { get; set; }
/// <summary>
/// 为404,代表Index不存在,已删除
/// </summary>
public int status { get; set; }
}
}