前言

  之前项目中做Elasticsearch相关开发的时候,虽然借助了第三方的组件PlainElastic.Net,但是由于当时不熟悉用法,而选择了自己拼接查询语句。例如:

            string queryGroup = "{\"query\": {\"match\": { \"roomid\": \"FRIEND_12686_10035\" }}}";
//关键字查询
string queryKeyWord = "{ \"query\": {\"match_phrase\": {\"content\": {\"query\": \"" + keyword + "\",\"slop\": 0} } }}";
//是否图片 查询
string queryImg = "{ \"term\": {\"isimg\": true }}";
//是否包含文件查询
string queryFile = "{ \"term\": {\"isfile\": true }}";
//大于小于某个时间段查询
string queryTimeRange = "{\"range\": {\"addtime\": { \"gt\": \"" + st + "\",\"lt\": \"" + et + "\" }} }";
//大于某个时间
string queryTimeRangeGt = "{\"range\": {\"addtime\": { \"gt\": \"" + st + "\"}} }";
//小于某个时间
string queryTimeRangeLt = "{\"range\": {\"addtime\": { \"lt\": \"" + et + "\" }} }";

  后来慢慢看了下该组件的源代码,想自己简单实现一下,看看到底是什么原理。

分析

  先来一个简单的小例子:PlainElastic中的demo示例:

      string query = new QueryBuilder<Tweet>()        // This will generate:
.Query(q => q // { "query": { "term": { "User": "somebody" } } }
.Term(t => t
.Field(tweet=> tweet.User).Value("somebody")
)
).Build();

  可以看到,构造查询语句的时候很灵活,直接用表达式的形式,最后通过Build方法,生成相应的查询语句,于是乎,照着葫芦画瓢,开始吧。其实,不管如何写语句,最终都是对字符串的拼接,生成最终的查询语句。那我们就从最简单的term查询开始。比如一条查询语句就是 {"query":{"term":{"name":"zhangsan"}}},这条语句的的意思,就是查询 name 为zhangsan的数据。(需要读者懂elasticsearch查询语法)

  先不考虑封装,直接新建一个类,就叫 TermFilter,内部实现了 Term 的语言构造。由于需要链式调用,所以里面的方法一般都返回  this 。

        private Dictionary<string, object> _terms;
public TermFilter()
{
_terms = new Dictionary<string, object>();
}
public TermFilter KeyValue(string key, object value)
{
_terms.Add(key, value);
return this;
}

  如上述代码所示,当我们调用KeyValue方法时,传入key和value,添加到内部的Dictionary中。然后重写 ToString 方法,构造Term语句

       private void Build()
{
StringBuilder str = new StringBuilder();
int i = ;
foreach (KeyValuePair<string, object> kv in _terms)
{
str.Append("{\"term\":{\"" + kv.Key + "\":" + kv.Value + "}}");
if (i >= && i < _terms.Count - )
{
str.Append(",");
}
i++;
}
_condition = str.ToString();
}
public override string ToString()
{
Build(); return base.ToString();
}

  遍历Dictionary,构造term语句,Term构造完之后,我们需要在外层加一个Query,由于Query是通用的,所以也需要提取出。于是乎,又多了一个类,叫做Filter,这个是查询的入口,里面有两个方法,一个Bool方法,一个Query方法:

     public Filter() { }
//
public Filter Bool(Func<BoolFilter, BoolFilter> boolFunc)
{
string boolFuncResult = boolFunc(new BoolFilter()).ToString();
_condition = "{\"query\":{\"filtered\":{\"filter\":{" + boolFuncResult + "}}}";
return this;
}
public Filter Query(Func<BoolFilter, BoolFilter> boolFunc)
{
string boolFuncResult = boolFunc(new BoolFilter()).ToString();
_condition = "{\"query\":" + boolFuncResult;
return this;
}

  直接看Query方法,里面的参数为 Func<BoolFilter,BoolFilter> boolFunc,好吧,这里的Boss终于出场了,就是核心类,BoolFilter,它内部实现了,Must,Shoud,MustNot,And,Or,等方法。当然还有Term。我们直接看Term方法。

 public BoolFilter Term(Func<TermFilter, TermFilter> termFunc)
{
PrapareCondition();
_condition += termFunc(new TermFilter());
return this;
}

  同理,因为链式调用,还是返回this,上述代码中由于termFunc 返回的是一个TermFilter对象,然后toString之后,就相当于追加 相应的Term语句。ToString方法最终也是返回 _condition字段的值。好吧,我猜你越来越晕了,没关系,我们在看最后一个类,就可以实战了。

      public QueryCreator Filter(Func<Filter, Filter> filter)
{
_condition += filter(new Filter());
return this;
}

  好了,到这里,代码基本结束了。重新梳理一遍:

  首先,最外层代码调用Filter方法,Filter实现了Query方法,Query内部传入了BoolFilter参数,在调用Term方法,最终由TermFilter实现语句的构造,所以,外部最终代码调用起来是这样的。

var result = creator.Filter(f =>  //Filter内部调用Query方法,
f.Query(q => //Query调用BoolFilter的Term方法
q.Term(t => //BoolFilter又调用TermFilter的KeyValue方法
t.KeyValue("name", "zhangsan"))))
.BuildBeautiful();//最后构造出我们想要的结果

  

如上图,from和size是默认的。下面我们来个稍微复杂点的。比如在一个用户表,想要查询 用户类型为 3 的且地区为 北京 的 并且满足 年龄是 20  岁或者 工作经验为1年 的用户。并且根据 姓名倒叙排序,分页取第3页的20条数据。

首先分析一下,这里我们要使用 and 查询,and 里面还包括  or 查询。 构造语句如下:

        var result = creator.Filter(f =>
f.Bool(b => //bool查询
b.Must(m => //must,必须符合条件
m.And(a => //and查询
a.Term(t => //构造查询条件
t.KeyValue("type", ).KeyValue("area", "北京")).
Or(o => o.Term(t1 => t1.KeyValue("age", ).KeyValue("experience", ))))))).//or查询,构造查询条件
Page().//页码
Size().//每页大小
OrderByDesc("name").//姓名倒叙排序
BuildBeautiful();//根据之前的条件创建查询语句

  哈哈,是不是有点绕啊,其实要想用这个,还是得会点ES查询语法的,就好比SQL语句一样,你不理解,是查不出东东的。用这种方式我们就能够避免手动写ES查询语句了,只要经过代码简单配制就好喽,不过我还是乖乖用第三方组件吧,自己写的太渣了。。。

看看构造成的语句:

好了就到这里吧。当做自己研究的总结了。

Func<T,T>应用之Elasticsearch查询语句构造器的开发的更多相关文章

  1. elasticsearch查询语句

    1,安装es 安装java环境 # java --versionjava version "1.8.0_65" Java(TM) SE Runtime Environment (b ...

  2. elasticsearch查询语句总结

    query 和  filter 的区别请看:https://www.cnblogs.com/bainianminguo/articles/10396956.html Filter DSL term 过 ...

  3. SpringBoot使用注解的方式构建Elasticsearch查询语句,实现多条件的复杂查询

    背景&痛点 通过ES进行查询,如果需要新增查询条件,则每次都需要进行硬编码,然后实现对应的查询功能.这样不仅开发工作量大,而且如果有多个不同的索引对象需要进行同样的查询,则需要开发多次,代码复 ...

  4. 常用ElasticSearch 查询语句

    为了演示不同类型的 ElasticSearch 的查询,我们将使用书文档信息的集合(有以下字段:title(标题), authors(作者), summary(摘要), publish_date(发布 ...

  5. 03005_SQL查询语句

    查询语句,在开发中使用的次数最多,此处使用“zhangwu” 账务表. 1.准备工作 (1)创建财务表: CREATE TABLE zhangwu ( id INT PRIMARY KEY AUTO_ ...

  6. ElasticSearch 论坛搜索查询语句

    概述 研究论坛搜索如何综合时间和TF/IDF权重. 自定义权重计算的效率问题 数据结构 假设有一个论坛的搜索 字段包括: subject:标题 message:内容 dateline:发布时间 tag ...

  7. ElasticSearch 7.X版本19个常用的查询语句

    整理一篇常用的CRUD查询语句,之前这篇文件是在17年左右发表的,从英文翻译过来,现在采用7.x 版本进行实验,弃用的功能或者参数,我这边会进行更新,一起来学习吧. 为了演示不同类型的 Elastic ...

  8. elasticsearch 查询(match和term)

    elasticsearch 查询(match和term) es中的查询请求有两种方式,一种是简易版的查询,另外一种是使用JSON完整的请求体,叫做结构化查询(DSL). 由于DSL查询更为直观也更为简 ...

  9. Elasticsearch 查询与过滤

    今天在给上级汇报工作的时候,被问到了这个问题,一时也没回到上来. 英文原文: https://www.elastic.co/guide/en/elasticsearch/guide/current/_ ...

随机推荐

  1. Head First 设计模式--1策略模式 组合优于继承

    策略模式:第一了算法族,分别封装起来,让他们之间可以互相替换,次模式让算法的变化独立于使用算法的客户. 首先看个错误的面向对象. 假如我们需要写一个关于鸭子的程序,各种类型的鸭子.第一想到的就是建一个 ...

  2. react mixins编写

    var LogMixin = { componentWillMount: function () { console.log('Component will mount'); }, component ...

  3. 第5章 Web自动化测试

    5.1 Selenium简介 5.1.1 自动化测试简介 5.1.2 Selenium简介 5.2 Selenium2环境搭建 5.3 Java基础 5.3.1 新建Java工程和类 5.3.2 Ec ...

  4. 如何有效使用Project(1)——编制进度计划、保存基准

    1.前言: 软件产品的研发.升级.定制等,一般都是以项目的形式进行,此时项目进度计划以及资源使用情况就变成了项目经理关注的重点.如何让项目计划有效可控,及时暴露问题?如何查看资源的负荷情况,看资源分配 ...

  5. Android 之 log

    android.util.Log常用方法: Log.v()  VERBOSE  任何消息都会输出 Log.d()  DEBUG  仅输出debug调试的意思,但他会输出上层的信息,过滤起来可以通过DD ...

  6. 【必备】史上最全的浏览器 CSS & JS Hack 手册(转)

    浏览器渲染页面的方式各不相同,甚至同一浏览器的不同版本(“杰出代表”是 IE)也有差异.因此,浏览器兼容成为前端开发人员的必备技能.如果有一份浏览器 Hack 手册,那查询起来就方便多了.这篇文章就向 ...

  7. WCF初探-6:WCF服务配置

    WCF服务配置是WCF服务编程的主要部分.WCF作为分布式开发的基础框架,在定义服务以及定义消费服务的客户端时,都使用了配置文件的方法.虽然WCF也提供硬编程的方式,通过在代码中直接设置相关对象的属性 ...

  8. qsort函数

    qsort函数用法举例 #include <stdio.h> #include <stdlib.h> #include <string.h> //数字比较函数 in ...

  9. 【61测试】【dp】【二分】【前缀和】【树剖】

    不要问我为什么昨天考的今天才贴解题报告.. 第一题: 给定3个字符串,求它们的最长公共子序列. 解: 考试时知道肯定是LCS的二维再加一维,用三维,可天堂有路你不走,地狱无门你偏来...灵机一动想出来 ...

  10. enmo_day_10

    RMAN 创建备份集 : backup as backupset format ‘/backup/df_%d_%s_%p/bus’ tablespace hr_data; 创建镜像副本 :(备份慢,恢 ...