• .Net Core中使用NEST简单操作Elasticsearch


    C#中访问Elasticsearch主要通过两个包NESTElasticsearch.NetNEST用高级语法糖封装了Elasticsearch.Net可以通过类Linq的方式进行操作,而Elasticsearch.Net相比之下更为原始直接非常自由。

    注意:ES8.X以上的版本有新的包Elastic.Clients.Elasticsearc支持。

    此处使用NEST,我们通过Nuget安装,如下图:

    1、准备结构

     准备以下实体

    复制代码
    public class Company
        {
            public string Id { get; set; }
            public string Name { get; set; }
            public string Description { get; set; }
            public User User { get; set; }
        }
        public class User
        {
            public string Name { get; set; }
            public int Gender { get; set; }
        }
    复制代码

    2、连接ES

     如果是单机连接如下代码,可以直接在Uri上指定账号密码,也可以使用ConnectionSettingsBasicAuthentication来配置账号密码:

    var singleNode = new Uri("http://elastic:123456@localhost:9200");
        var connSettings = new ConnectionSettings(singleNode);
      //connSettings.BasicAuthentication("elastic", "123456"); var esClient
    = new ElasticClient(connSettings);

    如果是多个节点集群则如下代码:

    复制代码
    var nodes = new Uri[]
        {
            new Uri("http://esNode1:9200"),
            new Uri("http://esNode2:9200"),
            new Uri("http://esNode3:9200")
        };
        var pool = new StaticConnectionPool(nodes);
        var settings = new ConnectionSettings(pool);
        var client = new ElasticClient(settings);
    复制代码

    3、创建索引

    索引名称必须符合规则否则创建会失败,比如索引只能小写,具体代码如下:

    var indexName = "my_index1";//索引名称
        var res = await esClient.Indices.CreateAsync(indexName, o => o.Map(g => g.AutoMap()));//映射结构

     也可以在向索引插入数据的时候自动判断是否存在索引,不存在会自动创建。索引结构字段映射一但创建就无法修改,可以通过新建索引然后转移数据的方式修改索引结构,但是可以往里面新增字段映射,比如修改了实体结构新的字段将会被映射。

    4、插入数据

    使用IndexDocumentAsync方法插入单条数据需要在ConnectionSettingsDefaultIndex方法设置默认索引。使用IndexAsync插入单条数据时需要选择指定索引,如下:

    复制代码
    var singleNode = new Uri("http://localhost:9200");
        var connSettings = new ConnectionSettings(singleNode);
        connSettings.BasicAuthentication("elastic", "123456");
        var esClient = new ElasticClient(connSettings.DefaultIndex("my_index1"));
        var indexName = "my_index1";
        var company = new Company()
        {
            Name = "超级公司bulk",
            Description = "超级描述bulk",
        };
        var res1 = await esClient.IndexDocumentAsync(company);
        var res2 = await esClient.IndexAsync(company, g => g.Index(indexName))    
    复制代码

     如果需要批量插入需要用BulkDescriptor对象包裹,然后使用BulkAsync方法插入,或者不要包裹直接用IndexManyAsync方法插入,具体如下:

    复制代码
    var company = new Company()
        {
            Name = "超级公司bulk",
            Description = "超级描述bulk"
        });
        BulkDescriptor descriptor = new BulkDescriptor();
        descriptor.Index(op => op.Document(company).Index(indexName));
        var res = await esClient.BulkAsync(descriptor);
        //var list = new List();
        //list.Add(company);
        //var res = await esClient.IndexManyAsync(list, indexName);  
    复制代码

     如果实体有Id则会使用Id的值做为_id的索引文档唯一值,或者可以通过手动指定如await esClient.IndexAsync(company, g => g.Index(indexName).Id(company.Id)),如果id相同执行插入操作则为更新不会重复插入。在新增后是会返回id等信息可以加以利用。

    5、删除数据

    删除指定单条数据需要知道数据的id,如下两种方式:

    DocumentPath deletePath = new DocumentPath(Guid.Empty);
        var delRes = await esClient.DeleteAsync(deletePath, g => g.Index(indexName));
        //或者
        IDeleteRequest request = new DeleteRequest(indexName, "1231");
        var delRes = await esClient.DeleteAsync(request);

     多条删除使用DeleteByQueryAsync方法进行匹配删除,下面两种方式等价,删除Description字段模糊查询有描述的数据(最多10条):

    复制代码
    var req = new DeleteByQueryRequest(indexName)
        {
            MaximumDocuments = 10,//一次最多删几条
            Query = new MatchQuery()
                    {
                        Field = "description",
                        Query = "描述"
                    }
        };
        var result = await esClient.DeleteByQueryAsync(req);
        //等价于
        var result = await esClient.DeleteByQueryAsync(dq =>
                        dq.MaximumDocuments(10).Query(
                                q => q.Match(tr => tr.Field(fd => fd.Description).Query("描述"))).Index(indexName)
                         );
    复制代码

     6、更新数据

     除了上述插入数据时自动根据id进行更新外还有以下的主动更新。

     根据id更新单条数据以下代码等价,可以更新部分字段值,但是_id是确定就不会更改的虽然对应的Id字段已被修改:

    复制代码
    DocumentPath deletePath = new DocumentPath("1231");
        var res = await esClient.UpdateAsync(deletePath ,(p) => p.Doc(company).Index(indexName));
        //等价于
        IUpdateRequest request = new UpdateRequest(indexName, "1231")
        {
            Doc = new Company()
            {
                Id = "888",
                Description = "11111",
            }
        };
        var res = await esClient.UpdateAsync(request);
    复制代码

     如果有多个id更新多条数据可以用如下方法:

    var res = esClient.Bulk(b => b.UpdateMany(new List() { new Company()
        {
            Id="1231",
        } }, (b, u) => b.Id(u.Id).Index(indexName).Doc(new Company { Name = "我无语了" })));

    通过条件批量更新如下,

    复制代码
    var req = new UpdateByQueryRequest(indexName)
        {
            MaximumDocuments = 10,//一次最多更新几条
            Query = new MatchQuery()
            {
                Field = "description",
                Query = "66",
            },
            Script = new ScriptDescriptor()
            .Source($"ctx._source.description = params.description;")
            .Params(new Dictionary<string, object>
            {
                { "description","小时了123123123"}
            }),
            Refresh = true
        };
        var result = await esClient.UpdateByQueryAsync(req);
    复制代码

     7、数据查询

    上文中的更新等都用到了查询过滤,此处就用网上的这个例子吧:

    复制代码
    var result = client.Search(
                    s => s
                        .Explain() //参数可以提供查询的更多详情。
                        .FielddataFields(fs => fs //对指定字段进行分析
                            .Field(p => p.vendorFullName)
                            .Field(p => p.cbName)
                        )
                        .From(0) //跳过的数据个数
                        .Size(50) //返回数据个数
                        .Query(q =>
                            q.Term(p => p.vendorID, 100) // 主要用于精确匹配哪些值,比如数字,日期,布尔值或 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("0").LessThan("1"))) //指定范围查找
                                    .Should(sd => sd //至少有一个分句匹配,与 OR 相同
                                        .Term(p => p.priceID, 32915),
                                        sd => sd.Terms(t => t.Field(fd => fd.priceID).Terms(new[] {10, 20, 30})),//多值
                                        //||
                                        //sd.Term(p => p.priceID, 1001)
                                        //||
                                        //sd.Term(p => p.priceID, 1005)
                                        sd => sd.TermRange(tr => tr.GreaterThan("10").LessThan("12").Field(f => f.vendorPrice))
                                    )
                                    .MustNot(mn => mn//所有分句都必须不匹配,与 NOT 相同
                                        .Term(p => p.priceID, 1001)
                                        ,
                                        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))) //返回特定的字段
                   );
        
    复制代码

     

  • 相关阅读:
    计算机网络面试大总结
    【深度学习基础】专业术语汇总(欠拟合和过拟合、泛化能力与迁移学习、调参和超参数、训练集、测试集和验证集)
    公益理发暖人心,爱心助老绿萝先行
    【web-解析目标】(1.1.1)解析内容和功能:web信息抓取
    【愚公系列】2022年11月 .NET CORE工具案例-使用MailKit使用IMAP协议进行邮件读取
    AI在商业逻辑应用中的革命性作用
    使用 k3d 在Windows上安装 k3s
    sublime删除特定内容所在行
    华为政企协作平板产品集
    禁止ios长按时触发系统的菜单,禁止ios&android长按时下载图片
  • 原文地址:https://www.cnblogs.com/xwc1996/p/17119378.html