点击“开发者技术前线”,选择“星标????”

让一部分开发者看到未来

回复“666”,获取一份技术人专属大礼包

参考:https://elasticstack.blog.csdn.net/article/details/105199768

Elasticsearch 是一个全文搜索引擎,具有您期望的所有优点,例如相关性评分,词干,同义词等。而且,由于它是具有水平可扩展的分布式文档存储,因此它可以处理数十亿行数据,而不会费劲。针对Elasticsearch专业人员来说,大多数人喜欢使用DSL来进行搜索,但是对于一些不是那么专业的人员来说,他们更为熟悉的是 SQL 语句。如何让他们对 Elasticsearch 的数据进行查询是一个问题。借助 Elasticsearch SQL,您可以使用熟悉的查询语法访问全文搜索,超快的速度和轻松的可伸缩性。X-Pack 包含一项 SQL 功能,可对 Elasticsearch 索引执行 SQL 查询并以表格格式返回结果。

在今天的文章里,我们将简单介绍一下如何使用 Elasticsearch SQL来对我们的数据进行查询。在之前的一篇文章“Kibana:Canvas入门”里也有 Elasticsearch SQL 的具体用例介绍。

安装

对于还没安装好自己的 Elasticsearch 的开发者来说,你可以参阅我之前的文章“Elastic:菜鸟上手指南”来进行安装自己的 Elasticsearch 及 Kibana。在这里我就不累述了。

准备数据

我们首先打开 Kibana:

点击上面的“Load a data set and a Kibana dashboard”:

点击上面的 Add data,这样我们就可以完成实验数据的导入了。在 Elasticsearch 中,我们会找到一个叫 kibana_sample_data_flights 的索引。

SQL 实操

检索 Elasticsearch schema 信息:DSL vs SQL

首先,我们确定表/索引的 schema 以及可供我们使用的字段。我们将通过 REST 界面执行此操作:

POST /_sql
{"query": """DESCRIBE kibana_sample_data_flights"""
}
上面命令的结果:{"columns" : [{"name" : "column","type" : "keyword"},{"name" : "type","type" : "keyword"},{"name" : "mapping","type" : "keyword"}],"rows" : [["AvgTicketPrice","REAL","float"],["Cancelled","BOOLEAN","boolean"],["Carrier","VARCHAR","keyword"],["Dest","VARCHAR","keyword"],["DestAirportID","VARCHAR","keyword"],["DestCityName","VARCHAR","keyword"],["DestCountry","VARCHAR","keyword"],["DestLocation","GEOMETRY","geo_point"],["DestRegion","VARCHAR","keyword"],["DestWeather","VARCHAR","keyword"],["DistanceKilometers","REAL","float"],["DistanceMiles","REAL","float"],["FlightDelay","BOOLEAN","boolean"],["FlightDelayMin","INTEGER","integer"],["FlightDelayType","VARCHAR","keyword"],["FlightNum","VARCHAR","keyword"],["FlightTimeHour","VARCHAR","keyword"],["FlightTimeMin","REAL","float"],["Origin","VARCHAR","keyword"],["OriginAirportID","VARCHAR","keyword"],["OriginCityName","VARCHAR","keyword"],["OriginCountry","VARCHAR","keyword"],["OriginLocation","GEOMETRY","geo_point"],["OriginRegion","VARCHAR","keyword"],["OriginWeather","VARCHAR","keyword"],["dayOfWeek","INTEGER","integer"],["timestamp","TIMESTAMP","datetime"]]
}

也可以通过 url 参数 format = txt 以表格形式格式化以上响应。例如:

POST /_sql?format=txt
{"query": "DESCRIBE kibana_sample_data_flights"
}

上面命令查询的结果是:

      column      |     type      |    mapping
------------------+---------------+---------------
AvgTicketPrice    |REAL           |float
Cancelled         |BOOLEAN        |boolean
Carrier           |VARCHAR        |keyword
Dest              |VARCHAR        |keyword
DestAirportID     |VARCHAR        |keyword
DestCityName      |VARCHAR        |keyword
DestCountry       |VARCHAR        |keyword
DestLocation      |GEOMETRY       |geo_point
DestRegion        |VARCHAR        |keyword
DestWeather       |VARCHAR        |keyword
DistanceKilometers|REAL           |float
DistanceMiles     |REAL           |float
FlightDelay       |BOOLEAN        |boolean
FlightDelayMin    |INTEGER        |integer
FlightDelayType   |VARCHAR        |keyword
FlightNum         |VARCHAR        |keyword
FlightTimeHour    |VARCHAR        |keyword
FlightTimeMin     |REAL           |float
Origin            |VARCHAR        |keyword
OriginAirportID   |VARCHAR        |keyword
OriginCityName    |VARCHAR        |keyword
OriginCountry     |VARCHAR        |keyword
OriginLocation    |GEOMETRY       |geo_point
OriginRegion      |VARCHAR        |keyword
OriginWeather     |VARCHAR        |keyword
dayOfWeek         |INTEGER        |integer
timestamp         |TIMESTAMP      |datetime

是不是感觉回到 SQL 时代啊:)

向前迈进,只要提供来自 REST api 的示例响应,我们就会使用上面显示的表格响应结构。要通过控制台实现相同的查询,需要使用以下命令登录:

./bin/elasticsearch-sql-cli http://localhost:9200

我们可在屏幕上看到如下的画面:

太神奇了。我们直接看到 SQL 的命令提示符了。在上面的命令行中,我们打入如下的命令:

DESCRIBE kibana_sample_data_flights;

这个结果和我们在Kibana中得到的结果是一样的。

上面的schema也会随对在 SELECT 子句中显示的字段的任何查询一起返回,从而为任何潜在的驱动程序提供格式化或对结果进行操作所需的必要类型信息。例如,考虑带有 LIMIT 子句的简单 SELECT,以使响应简短。默认情况下,我们返回1000行。

我们发现索引的名字 kibana_sample_data_flights 比较长,为了方便,我们来创建一个alias:

PUT /kibana_sample_data_flights/_alias/flights

这样在以后的操作中,当我们使用flights的时候,其实也就是对索引kibana_sample_data_flights 进行操作。

我们执行如下的命令:

POST /_sql?format=txt
{"query": "SELECT FlightNum FROM flights LIMIT 1"
}

显示结果:

   FlightNum
---------------
9HY9SWR

相同的REST请求/响应由JDBC驱动程序和控制台使用:

sql> SELECT OriginCountry, OriginCityName FROM flights LIMIT 1;OriginCountry | OriginCityName
---------------+-----------------
DE             |Frankfurt am Main

请注意,如果在任何时候请求的字段都不存在(区分大小写),则表格式和强类型存储区的语义意味着将返回错误-这与 Elasticsearch 行为不同,在该行为中,根本不会返回该字段。例如,将上面的内容修改为使用字段“OrigincityName”而不是“OriginCityName”会产生有用的错误消息:

sql> SELECT OriginCountry, OrigincityName FROM flights LIMIT 1;
Bad request [Found 1 problem(s)
line 1:23: Unknown column [OrigincityName], did you mean any of [OriginCityName, DestCityName]?]

同样,如果我们尝试在不兼容的字段上使用函数或表达式,则会出现相应的错误。通常,分析器在验证 AST 时会较早失败。为了实现这一点,Elasticsearch 必须了解每个字段的索引映射和功能。因此,任何具有安全性访问 SQL 接口的客户端都需要适当的权限。

如果我们继续提供每一个请求和相应的回复,我们将最终获得一篇冗长的博客文章!为了简洁起见,以下是一些带有感兴趣的注释的日益复杂的查询。

使用 WHERE 及 ORDER BY 来 SELECT

“找到飞行时间超过5小时的美国最长10班航班。”

POST /_sql?format=txt
{"query": """SELECT OriginCityName, DestCityName FROM flights WHERE FlightTimeHour > 5 AND OriginCountry='US' ORDER BY FlightTimeHour DESC LIMIT 10"""
}

显示结果是:

OriginCityName |   DestCityName
---------------+-------------------
Chicago        |Oslo
Cleveland      |Seoul
Denver         |Chitose / Tomakomai
Nashville      |Verona
Minneapolis    |Tokyo
Portland       |Treviso
Spokane        |Vienna
Kansas City    |Zurich
Kansas City    |Shanghai
Los Angeles    |Zurich

限制行数的运算符因 SQL 实现而异。对于 Elasticsearch SQL,我们在实现LIMIT运算符时与 Postgresql/Mysql 保持一致。

Math

只是一些随机数字...

sql> SELECT ((1 + 3) * 1.5 / (7 - 6)) * 2 AS random;random
---------------
12.0

这代表服务器端对功能执行某些后处理的示例。没有等效的Elasticsearch DSL查询。

Functions & Expressions

“在2月份之后查找所有航班,该航班的飞行时间大于5小时,并且按照时间最长来排序。”

POST /_sql?format=txt
{"query": """SELECT MONTH_OF_YEAR(timestamp), OriginCityName, DestCityName FROM flights WHERE FlightTimeHour > 1 AND MONTH_OF_YEAR(timestamp) > 2 ORDER BY FlightTimeHour DESC LIMIT 10"""
}

显示结果是:

MONTH_OF_YEAR(timestamp)|OriginCityName | DestCityName
------------------------+---------------+---------------
4                       |Chicago        |Oslo
4                       |Osaka          |Spokane
4                       |Quito          |Tucson
4                       |Shanghai       |Stockholm
5                       |Tokyo          |Venice
5                       |Tokyo          |Venice
5                       |Tokyo          |Venice
5                       |Buenos Aires   |Treviso
5                       |Amsterdam      |Birmingham
5                       |Edmonton       |Milan

这些功能通常需要在 Elasticsearch 中运用 Painless 变形才能达到等效的效果,而 SQL 的功能声明避免任何脚本编写。还要注意我们如何在WHERE和SELECT子句中使用该函数。WHERE 子句组件被下推到 Elasticsearch,因为它影响结果计数。SELECT 函数由演示中的服务器端插件处理。

请注意,可用功能列表可通过“SHOW FUNCTIONS”检索

sql> SHOW FUNCTIONS;name       |     type
-----------------+---------------
AVG              |AGGREGATE
COUNT            |AGGREGATE
FIRST            |AGGREGATE
FIRST_VALUE      |AGGREGATE
LAST             |AGGREGATE
LAST_VALUE       |AGGREGATE
MAX              |AGGREGATE ...

将其与我们之前的数学能力相结合,我们可以开始制定查询,对于大多数DSL用户来说,查询将非常复杂。

“找出最快的2个航班(速度)的距离和平均速度,这些航班在星期一,星期二或星期三上午9点至11点之间离开,并且距离超过500公里。将距离和速度四舍五入到最接近的整数。如果速度相等,请先显示最长的时间。”

首先我们在上面的 DESCRIBE kibana_sample_data_flights 命令的输出中,我们可以看到FlightTimeHour 是一个 keyword。这个显然是不对的,因为它是一个数值。也许在最初的设计时这么想的。我们需要把这个字段改为 float 类型的数据。

PUT flight1
{"mappings": {"properties": {"AvgTicketPrice": {"type": "float"},"Cancelled": {"type": "boolean"},"Carrier": {"type": "keyword"},"Dest": {"type": "keyword"},"DestAirportID": {"type": "keyword"},"DestCityName": {"type": "keyword"},"DestCountry": {"type": "keyword"},"DestLocation": {"type": "geo_point"},"DestRegion": {"type": "keyword"},"DestWeather": {"type": "keyword"},"DistanceKilometers": {"type": "float"},"DistanceMiles": {"type": "float"},"FlightDelay": {"type": "boolean"},"FlightDelayMin": {"type": "integer"},"FlightDelayType": {"type": "keyword"},"FlightNum": {"type": "keyword"},"FlightTimeHour": {"type": "float"},"FlightTimeMin": {"type": "float"},"Origin": {"type": "keyword"},"OriginAirportID": {"type": "keyword"},"OriginCityName": {"type": "keyword"},"OriginCountry": {"type": "keyword"},"OriginLocation": {"type": "geo_point"},"OriginRegion": {"type": "keyword"},"OriginWeather": {"type": "keyword"},"dayOfWeek": {"type": "integer"},"timestamp": {"type": "date"}}}
}

我们需要 reindex 这个索引。

POST _reindex
{"source": {"index": "flights"},"dest": {"index": "flight1"}
}

那么现在 flight1 的数据中,FlightTimeHour 字段将会是一个 float 的类型。我们再次重新设置 alias 为 flights:

POST _aliases
{"actions": [{"add": {"index": "flight1","alias": "flights"}},{"remove": {"index": "kibana_sample_data_flights","alias": "flights"}}]
}

那么现在 flights 将是指向 flight1 的一个 alias。

我们使用如下的 SQL 语句来查询:

sql> SELECT timestamp, FlightNum, OriginCityName, DestCityName, ROUND(DistanceMiles) AS distance, ROUND(DistanceMiles/FlightTimeHour) AS speed, DAY_OF_WEEK(timestamp) AS day_of_week FROM flights WHERE DAY_OF_WEEK(timestamp) >= 0 AND DAY_OF_WEEK(timestamp) <= 2 AND HOUR_OF_DAY(timestamp) >=9 AND HOUR_OF_DAY(timestamp) <= 10 ORDER BY speed DESC, distance DESC LIMIT 2;timestamp        |   FlightNum   |OriginCityName | DestCityName  |   distance    |     speed     |  day_of_week
------------------------+---------------+---------------+---------------+---------------+---------------+---------------
2020-05-17T10:53:52.000Z|LAJSKLT        |Guangzhou      |Lima           |11398.0        |783.0          |1
2020-04-27T09:30:39.000Z|VLUDO2H        |Buenos Aires   |Moscow         |8377.0         |783.0          |2

一个相当复杂且奇怪的问题,但希望您能明白这一点。还要注意我们如何创建字段别名并在ORDER BY 子句中引用它们。

还要注意,不需要在 SELECT 子句中指定 WHERE 和 ORDER BY 中使用的所有字段。这可能与您过去使用的 SQL 实现不同。例如,以下内容完全正确:

POST /_sql
{"query":"SELECT timestamp, FlightNum FROM flights WHERE AvgTicketPrice > 500 ORDER BY AvgTicketPrice"
}

它显示:

{"columns" : [{"name" : "timestamp","type" : "datetime"},{"name" : "FlightNum","type" : "text"}],"rows" : [["2020-04-26T09:04:20.000Z","QG5DXD3"],["2020-05-02T23:18:27.000Z","NXA71BT"],["2020-04-17T01:55:18.000Z","VU8K9DM"],["2020-04-24T08:46:45.000Z","UM8IKF8"],
...
]

将SQL查询转换为DSL

我们都曾尝试过要在 Elasticsearch DSL 中表达的 SQL 查询,或者想知道它是否是最佳的。新 SQL 接口的引人注目的功能之一是它能够协助 Elasticsearch 的新采用者解决此类问题。使用 REST 接口,我们只需将/translate附加到“sql”端点,即可获取驱动程序将发出的Elasticsearch 查询。

让我们考虑一下以前的一些查询:

POST /_sql/translate
{"query": "SELECT OriginCityName, DestCityName FROM flights WHERE FlightTimeHour > 5 AND OriginCountry='US' ORDER BY FlightTimeHour DESC LIMIT 10"
}

对于任何有经验的 Elasticsearch 用户,等效的 DSL 都应该是显而易见的:

{"size" : 10,"query" : {"bool" : {"must" : [{"range" : {"FlightTimeHour" : {"from" : 5,"to" : null,"include_lower" : false,"include_upper" : false,"boost" : 1.0}}},{"term" : {"OriginCountry.keyword" : {"value" : "US","boost" : 1.0}}}],"adjust_pure_negative" : true,"boost" : 1.0}},"_source" : {"includes" : ["OriginCityName","DestCityName"],"excludes" : [ ]},"sort" : [{"FlightTimeHour" : {"order" : "desc","missing" : "_first","unmapped_type" : "float"}}]
}

WHERE 子句将按您期望的那样转换为 range 和 term 查询。请注意,子字段的OriginCountry.keyword变体如何用于与父代 OriginCountry(文本类型)的精确匹配。不需要用户知道基础映射的行为差异-正确的字段类型将会被自动选择。有趣的是,该接口尝试通过在 _source 上使用 docvalue_fields 来优化检索性能,例如适用于启用了 doc 值的确切类型(数字,日期,关键字)。我们可以依靠 Elasticsearch SQL 为指定的查询生成最佳的 DSL。

现在考虑我们上次使用的最复杂的查询:

POST /_sql/translate
{"query": """SELECT timestamp, FlightNum, OriginCityName, DestCityName, ROUND(DistanceMiles) AS distance, ROUND(DistanceMiles/FlightTimeHour) AS speed, DAY_OF_WEEK(timestamp) AS day_of_week FROM flights WHERE DAY_OF_WEEK(timestamp) >= 0 AND DAY_OF_WEEK(timestamp) <= 2 AND HOUR_OF_DAY(timestamp) >=9 AND HOUR_OF_DAY(timestamp) <= 10 ORDER BY speed DESC, distance DESC LIMIT 2"""
}

上面的响应为:

{"size" : 2,"query" : {"bool" : {"must" : [{"script" : {"script" : {"source" : "InternalSqlScriptUtils.nullSafeFilter(InternalSqlScriptUtils.and(InternalSqlScriptUtils.gte(InternalSqlScriptUtils.dateTimeChrono(InternalSqlScriptUtils.docValue(doc,params.v0), params.v1, params.v2), params.v3), InternalSqlScriptUtils.lte(InternalSqlScriptUtils.dateTimeChrono(InternalSqlScriptUtils.docValue(doc,params.v4), params.v5, params.v6), params.v7)))","lang" : "painless","params" : {"v0" : "timestamp","v1" : "Z","v2" : "HOUR_OF_DAY","v3" : 9,"v4" : "timestamp","v5" : "Z","v6" : "HOUR_OF_DAY","v7" : 10}},"boost" : 1.0}},{"script" : {"script" : {"source" : "InternalSqlScriptUtils.nullSafeFilter(InternalSqlScriptUtils.and(InternalSqlScriptUtils.gte(InternalSqlScriptUtils.dayOfWeek(InternalSqlScriptUtils.docValue(doc,params.v0), params.v1), params.v2), InternalSqlScriptUtils.lte(InternalSqlScriptUtils.dayOfWeek(InternalSqlScriptUtils.docValue(doc,params.v3), params.v4), params.v5)))","lang" : "painless","params" : {"v0" : "timestamp","v1" : "Z","v2" : 0,"v3" : "timestamp","v4" : "Z","v5" : 2}},"boost" : 1.0}}],"adjust_pure_negative" : true,"boost" : 1.0}},"_source" : {"includes" : ["FlightNum","OriginCityName","DestCityName","DistanceMiles","FlightTimeHour"],"excludes" : [ ]},"docvalue_fields" : [{"field" : "timestamp","format" : "epoch_millis"}],"sort" : [{"_script" : {"script" : {"source" : "InternalSqlScriptUtils.nullSafeSortNumeric(InternalSqlScriptUtils.round(InternalSqlScriptUtils.div(InternalSqlScriptUtils.docValue(doc,params.v0),InternalSqlScriptUtils.docValue(doc,params.v1)),params.v2))","lang" : "painless","params" : {"v0" : "DistanceMiles","v1" : "FlightTimeHour","v2" : null}},"type" : "number","order" : "desc"}},{"_script" : {"script" : {"source" : "InternalSqlScriptUtils.nullSafeSortNumeric(InternalSqlScriptUtils.round(InternalSqlScriptUtils.docValue(doc,params.v0),params.v1))","lang" : "painless","params" : {"v0" : "DistanceMiles","v1" : null}},"type" : "number","order" : "desc"}}]
}

是不是觉得非常复杂啊?

我们的 WHERE 和 ORDER BY 子句已转换为 painless 脚本,并在 Elasticsearch 提供的排序和脚本查询中使用。这些脚本甚至被参数化以避免编译并利用脚本缓存。

附带说明一下,尽管以上内容代表了 SQL 语句的最佳翻译,但并不代表解决更广泛问题的最佳解决方案。实际上,我们希望在索引时间对文档中的星期几,一天中的小时和速度进行编码,因此可以只使用简单的范围查询。这可能比使用painless 脚本解决此特定问题的性能更高。实际上,由于这些原因,其中的某些字段实际上甚至已经存在于文档中。这是用户应注意的常见主题:尽管我们可以依靠 Elasticsearch SQL 实现为我们提供最佳翻译,但它只能利用查询中指定的字段,因此不一定能为更大的问题查询提供最佳解决方案。为了实现最佳方法,需要考虑基础平台的优势,而 _translate API 可能是此过程的第一步。

END前线推出学习交流群,加群一定要备注:研究/工作方向+地点+学校/公司+昵称(如大数据+上海+携程+可可),根据格式备注,可更快被通过且邀请进群,领取一份专属学习礼包扫码家助理微信进群,内推和技术交流,大佬们零距离

面试官发难,如何用 SQL 来查询 Elasticsearch 中的数据?相关推荐

  1. 如何用 SQL 来查询 Elasticsearch 中的数据?

    大点击"开发者技术前线",选择"星标" 在看|星标|留言,  真爱 回复"666",获取一份技术人专属大礼包 参考:https://elas ...

  2. 如何用你最熟悉的 SQL 来查询 Elasticsearch 中的数据?

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! Elasticsearch 是一个全文搜索引擎,具有您期 ...

  3. oracle匹配excel数据,如何用Excel直接查询Oracle中的数据

    如何用Excel直接查询Oracle中的数据 关注:275  答案:2  mip版 解决时间 2021-01-11 08:35 提问者╬═掵中注定 2021-01-10 16:43 如何用Excel直 ...

  4. 如何用Excel直接查询Oracle中的数据(转)

    将Oracle中查询的数据保存为Excel文件,通常使用的是PL/SQL Developer. 其实,Excel可直接写SQL语句查询Oracle中数据,在这里,用到ODBC驱动.详细步骤如下: 一. ...

  5. 面试官:编写一个 SQL 查询,找出每个部门工资第二高的员工

    今天我们来看看大数据开发中row_number函数. 作为一名程序员,求职面试时时常会遇到需要编写一些基础的sql,编写sql这样做的目的主要是考验求职者的逻辑思维及编写sql基础能力.而row_nu ...

  6. java执行sql文件_面试官问你MyBatis SQL是如何执行的?把这篇文章甩给他

    初识 MyBatis MyBatis 是第一个支持自定义 SQL.存储过程和高级映射的类持久框架.MyBatis 消除了大部分 JDBC 的样板代码.手动设置参数以及检索结果.MyBatis 能够支持 ...

  7. 如何用SQL语句查询Excel数据

    Q:如何用SQL语句查询Excel数据? A:下列语句可在SQL SERVER中查询Excel工作表中的数据. 2007和2010版本: SELECT *  FROM OpenDataSource(  ...

  8. excel mysql 参数查询语句_如何用SQL语句查询Excel数据?

    如何用SQL语句查询Excel数据? Q:如何用SQL语句查询Excel数据? A:下列语句可在SQL SERVER中查询Excel工作表中的数据. 2007和2010版本: SELECT*FROMO ...

  9. excel mysql 参数查询语句_如何用SQL语句查询Excel数据

    Q:如何用SQL语句查询Excel数据? A:下列语句可在SQL SERVER中查询Excel工作表中的数据. 2007和2010版本: SELECT * FROM OpenDataSource( ' ...

最新文章

  1. linux 修改home 目录
  2. latex中的各种文件
  3. 树莓派10年销量4600万台!儿童玩具到工业设备它都可,创始人:最初只想造廉价电脑,不料第一天就卖出10万台...
  4. 单点登录之实战CAS5.1.x(六)——REST协议
  5. DCMTK:简单存储服务类提供者
  6. leetcode 375. Guess Number Higher or Lower II | 375. 猜数字大小 II(动态规划思路总结)
  7. 学习响应式BootStrap来写融职教育网站,Bootsrtap第十二天侧边卡片和列表组
  8. 如何查看某个employee被assign到了哪个sales organization上
  9. Promise 的基本使用 与 Ajax的jQuery封装
  10. java中文乱码解决之道(五)—–java是如何编码解码的
  11. 【渝粤教育】国家开放大学2019年春季 1161开放英语3 参考试题
  12. 前端学习(3010):vue+element今日头条管理--回顾
  13. 解决Maven打包(编译)慢的问题
  14. 一本关于HTTP的恋爱日记
  15. 手机里的html文档是什么,华为手机中后面带HTML的文档能删除吗?
  16. 工信部:短信可为 16 亿用户提供行程证明;OPPO 回应造芯计划;Windows Terminal 0.9 发布| 极客头条...
  17. 好友伤害_家暴,对一个孩子的伤害到底有多大?
  18. Spark大数据计算框架知识总结
  19. 基于京东家电商品知识图谱的自动问答系统(二) -- IDEA搭建开发环境
  20. php员工信息表_一键:快速采集汇总个税专项附加扣除信息

热门文章

  1. Git本地仓库与远程仓库链接
  2. 从传统框架到服务化框架
  3. 迪杰斯特拉(Dijkstra) —— 最短路算法
  4. 【JavaScript】关于js中performance性能监控
  5. imfinfo matlab,MATLAB函数imfinfo函数
  6. Unity优化之遮挡剔除Occlusion Culling
  7. Android之AlarmManager
  8. mipi接口LCD调试流程(基于Android4.0版本以后)
  9. vue新手建议学习路线
  10. 高中毕业屌丝程序员的逆袭之旅