首页 文章 精选 留言 我的

精选列表

搜索[笔记工具],共10000篇文章
优秀的个人博客,低调大师

ES7学习笔记(九)搜索

搜索是ES最最核心的内容,没有之一。前面章节的内容,索引、动态映射、分词器等都是铺垫,最重要的就是最后点击搜索这一下。下面我们就看看点击搜索这一下的背后,都做了哪些事情。 分数(score) ES的搜索结果是按照相关分数的高低进行排序的,咦?! 怎么没说搜索先说搜索结果的排序了?咱们这里先把这个概念提出来,因为在搜索的过程中,会计算这个分数。这个分数代表了这条记录匹配搜索内容的相关程度。分数是一个浮点型的数字,对应的是搜索结果中的_score字段,分数越高代表匹配度越高,排序越靠前。 在ES的搜索当中,分为两种,一种计算分数,而另外一种是不计算分数的。 查询(query context) 查询,代表的是这条记录与搜索内容匹配的怎么样,除了决定这条记录是否匹配外,还要计算这条记录的相关分数。这个和咱们平时的查询是一样的,比如我们搜索一个关键词,分词以后匹配到相关的记录,这些相关的记录都是查询的结果,那这些结果谁排名靠前,谁排名靠后呢?这个就要看匹配的程度,也就是计算的分数。 过滤(filter context) 过滤,代表的含义非常的简单,就是YES or NO,这条记录是否匹配查询条件,它不会计算分数。频繁使用的过滤还会被ES加入到缓存,以提升ES的性能。下面我们看一个查询和过滤的例子,这个也是ES官网中的例子。 GET /_search { "query": { "bool": { "must": [ { "match": { "title": "Search" }}, { "match": { "content": "Elasticsearch" }} ], "filter": [ { "term": { "status": "published" }}, { "range": { "publish_date": { "gte": "2015-01-01" }}} ] } } } 我们看一下请求的路径/_search,这个是请求的路径,而请求的方法是GET,我们再看请求体中,有一个query,这个代表着查询的条件。而bool中的must被用作query context,它在查询的时候会计算记录匹配的相关分数。filter中的条件用作过滤,只会把符合条件的记录检索出来,不会计算分数。 组合查询 组合查询包含了其他的查询,像我们前面提到的query context和filter context。在组合查询中,分为很多种类型,我们挑重点的类型给大家介绍一下。 Boolean Query boolean查询,前面我们写的查询语句就是一个boolean查询,boolean查询中有几个关键词,表格如下: 关键词 描述 must 必须满足的条件,而且会计算分数, filter 必须满足的条件,不会计算分数 should 可以满足的条件,会计算分数 must_not 必须不满足的条件,不会计算分数 我们看看下面的查询语句: POST _search { "query": { "bool" : { "must" : { "term" : { "user" : "kimchy" } }, "filter": { "term" : { "tag" : "tech" } }, "must_not" : { "range" : { "age" : { "gte" : 10, "lte" : 20 } } }, "should" : [ { "term" : { "tag" : "wow" } }, { "term" : { "tag" : "elasticsearch" } } ], "minimum_should_match" : 1, "boost" : 1.0 } } } 上面的查询是一个典型的boolean组合查询,里边的关键词都用上了。很多小伙伴们可能对must和should的区别不是很了解,must是必须满足的条件,我们的例子中must里只写了一个条件,如果是多个条件,那么里边的所有条件必须满足。而should就不一样了,should里边现在列出了两个条件,并不是说这两个条件必须满足,到底需要满足几个呢?我们看一下下面的关键字minimum_should_match,从字面上我们就可以看出它的含义,最小should匹配数,在这里设置的是1,也就是说,should里的条件只要满足1个,就算匹配成功。在boolean查询中,如果存在一个should条件,而没有filter和must条件的话,那么minimum_should_match的默认值是1,其他情况默认值是0。 我们再看一个实际的例子吧,还记得前面我们创建的ik_index索引吗?索引中存在着几条数据,数据如下: _index _type _id ▲_score id title desc ik_index _doc fEsN-HEBZl0Dh1ayKWZb 1 1 苹果 苹果真好吃 ik_index _doc 2 1 1 香蕉 香蕉真好吃 ik_index _doc 1 1 1 香蕉 香蕉真好吃 ik_index _doc 3 1 1 橘子 橘子真好吃 ik_index _doc 4 1 1 桃子 桃子真好吃 只有5条记录,我们新建一个查询语句,如下: POST /ik_index/_search { "query":{ "bool":{ "must":[ { "match":{ "desc":"香蕉好吃" } } ] } }, "from":0, "size":10, } 我们查询的条件是desc字段满足香蕉好吃,由于我们使用的ik分词器,查询条件香蕉好吃会被分词为香蕉和好吃,但是5的数据的desc中都有好吃字段,所有5条数据都会被查询出来,我们执行一下,看看结果: _index _type _id ▲_score id title desc ik_index _doc 2 0.98773474 1 香蕉 香蕉真好吃 ik_index _doc 1 0.98773474 1 香蕉 香蕉真好吃 ik_index _doc 3 0.08929447 1 橘子 橘子真好吃 ik_index _doc 4 0.08929447 1 桃子 桃子真好吃 ik_index _doc fEsN-HEBZl0Dh1ayKWZb 0.07893815 1 苹果 苹果真好吃 哈哈,5条数据全部查询出来了,和我们的预期是一样的,但是,我们需要注意一点的是_score字段,它们的分数是不一样的,我们的查询条件是香蕉好吃,所以既包含香蕉又包含好吃的数据分数高,我们看到分数到了0.98,而另外3条数据只匹配了好吃,所以分数只有0.7,0.8。 Boosting Query 这个查询比较有意思,它有两个关键词positive和negative,positive是“正”,所有满足positive条件的数据都会被查询出来,negative是“负”,满足negative条件的数据并不会被过滤掉,而是会扣减分数。那么扣减分数要扣减多少呢?这里边有另外一个字段negative_boost,这个字段是得分的系数,它的分数在0~1之间,满足了negative条件的数据,它们的分数会乘以这个系数,比如这个系数是0.5,原来100分的数据如果满足了negative条件,它的分数会乘以0.5,变成50分。我们看看下面的例子, POST /ik_index/_search { "query": { "boosting": { "positive": { "term": { "desc": "好吃" } }, "negative": { "term": { "desc": "香蕉" } }, "negative_boost": 0.5 } } } positive条件是好吃,只要desc中有“好吃”的数据都会被查询出来,而negative的条件是香蕉,只要desc中包含“香蕉”的数据都会被扣减分数,扣减多少分数呢?它的得分将会变为原分数*0.5。我们执行一下,看看效果, index type _id score _source.id source.title source.desc ik_index _doc 3 0.08929447 1 橘子 橘子真好吃 ik_index _doc 4 0.08929447 1 桃子 桃子真好吃 ik_index _doc fEsN-HEBZl0Dh1ayKWZb 0.07893815 1 苹果 苹果真好吃 ik_index _doc 2 0.044647235 1 香蕉 香蕉真好吃 ik_index _doc 1 0.044647235 1 香蕉 香蕉真好吃 我们可以看到前3条数据的分数都在0.09左右,而后两条的数据在0.044左右,很显然,后两条数据中的desc包含香蕉,它们的得分会乘以0.5的系数,所以分数只有前面数据的分数的一半。 全文检索 在前面几节的内容中,我们介绍过,只有字段的类型是text,才会使用全文检索,全文检索会使用到分析器,在我们的ik_index索引中,title和desc字段都是text类型,所以,这两个字段的搜索都会使用到ik中文分词器。全文检索比起前面的组合检索要简单一点,当然,在ES的官方文档中,全文检索中的内容还是挺多的,在这里我们只介绍一个标准的全文检索。 我们看看下面的语句, POST /ik_index/_search { "query": { "match": { "desc": { "query": "苹果" } } } } 在请求体中,match代替了之前的bool,match是标准的全文索引的查询。match后面跟的字段是要查询的字段名,在咱们的例子中,查询的字段是desc,如果有多个字段,可以列举多个。desc字段里,query就是要查询的内容。我们还可以在字段中指定分析器,使用analyzer关键字,如果不指定,默认就是索引的分析器。我们执行一下上面的查询,结果如下: index type _id score source.id source.title source.desc ik_index _doc fEsN-HEBZl0Dh1ayKWZb 1.2576691 1 苹果 苹果真好吃 我们可以看到相应的数据已经检索出来了。 最后 在ES中,检索的花样是比较多的,这里也不能一一给大家介绍了,只介绍一些最基本、最常用的查询功能。下一篇我们看一下ES的聚合查询功能。

优秀的个人博客,低调大师

工业互联网安全研究笔记

工业互联网作为我国打造制造强国的核心手段,也是最近大家谈论很多的“新基建”之一。那么,咱们今天要谈的工业互联网安全,它的防护对象有哪些呢? 总的来说,工业互联网安全防护的对象包括工业现场设备、工业控制系统、网络基础设施、工业应用程序及工业数据等,如下图: 确定了保护对象后,我们应该怎么来部署防护措施呢。 【理论基础安全篇】 第一,设备安全。在使用诸如工业机器人、智能仪表、传感器等现场设备时,主要的安全考虑是做好鉴权和控制。安全措施有: (1)采用鉴别机制对接入工业互联网中的设备身份进行鉴别,确保数据来源于真实的设备; (2)制定安全策略,如访问控制列表,实现对接入工业互联网中设备的访问控制,并对管理设备的用户授予其所需的最小权限,并实现对管理设备的用户的权限分离; (3)对登录设备的用户进行身份标识和鉴别,身份鉴别信息满足相应的复杂度要求并定期更换; (4)对设备配置登录失败处理功能,启用结束会话、限制非法登录次数和当登录连接超时自动退出等相关措施; (5)做好设备的用户管理工作,如账户和权限的管理、默认账户的管理、过期账户的管理等; (6)对设备采取基本的入侵防范措施,如只安装执行任务所必需的组件和应用程序,关闭设备中不需要的系统服务、默认共享和高危端口; (7)设定终端接入方式或网络地址范围对通过网络进行管理的终端进行限制; (8)及时修补漏洞; (9)对设备进行安全审计,审计覆盖到对设备进行运维的每个用户,对重要的用户行为和重要安全事件进行审计,做好审计记录的管理; 第二,控制安全。对于传统制造业来说,为保证整条流水线的协同生产,每个工厂都有着严格的流程控制,这也是为什么控制安全在整个工业互联网中同样占有重要作用的原因。在控制安全方面,主要对控制软件和控制协议采取安全措施: (1)对登录控制软件进行操作的用户进行身份标识和鉴别,身份鉴别信息满足相应的复杂度要求并定期更换; (2)对登录控制软件进行操作的过程配置登录失败处理功能,并启用结束会话、限制非法登录次数和当登录连接超时自动退出等相关措施; (3)做好控制软件的用户管理工作,如账户和权限的管理、默认账户的管理、过期账户的管理等; (4)对控制软件启用安全审计功能,审计记录符合法律法规要求; (5)对控制软件采取基本的入侵防范措施,如只安装必需的组件和程序,关闭设备中不需要的系统服务、默认共享和高危端口; (6)对控制协议采取完整性保证机制,确保控制协议中的各类指令不被非法篡改和破坏; (7)安装防恶意代码软件或配置具有相应功能的软件,并定期进行升级和更新防恶意代码库; (8)采取资源控制策略,限制单个用户或进程对系统资源的最大使用限度。 第三,网络安全。主要针对工厂内部和外部的网络及边界采取安全措施,防止来自外部的入侵: (1)内部网络。根据业务特点划分为不同的安全域,安全域之间应采用技术隔离手段。以及采用适应工厂内部网络特点的完整性校验机制,实现对网络数据传输完整性保护; (2)外部网络。保障数据传输过程中的保密性和完整性,可采取信道加密技术或部署加密机等方式; (3)网络边界安全。厘清内、外网之间的边界范围,针对边界采取安全相适应的措施,如在边界处设置工控防火墙、网闸、网关等安全隔离设备,并在关键网络节点处部署入侵防范设备。 (4)对网络通讯数据、访问异常、业务操作异常、网络和设备流量、工作周期、抖动值、运行模式、各站点状态、冗余机制等进行监测,发生异常进行报警; (5)对通过无线网络攻击的潜在威胁和可能产生的后果进行风险分析,并对可能遭受无线攻击的设备的信息发出(信息外泄)和进入(非法操控)进行屏蔽; (6)对网络进行安全审计,审计覆盖到每个用户,对重要的用户行为和重要安全事件进行审计; (7)实现网络集中管控,包括对网络链路、安全设备、网络设备和服务器等的运行状况进行集中监测。 第四,应用安全。针对工业互联网平台与工业应用程序至少需要采取身份鉴别和访问控制技术。 (1)对使用工业互联网平台与工业应用程序的用户身份进行标识和鉴别,身份鉴别信息满足复杂度要求并定期更换,强制用户首次登录时修改初始口令; (2)工业互联网平台及工业应用程序的登录过程应提供并启用登录失败处理功能,多次登录失败后应采取必要的保护措施; (3)对使用工业互联网平台及工业应用程序的用户分配账户及明确相应的访问操作权限,根据访问控制策略,对工业互联网平台开发者、工业应用程序及其用户调用工业互联网平台开发接口实施访问控制,并做好用户管理工作; (4)对于工业互联网平台及工业应用程序需配备数据合规性检验功能,保证通过人机接口输入或通过通信接口输入的内容符合其设定要求; (5)工业互联网平台与工业应用程序能提供安全审计功能,并在工业互联网平台及工业应用程序上线前对其安全性进行测试,对可能存在的恶意代码进行检测; (6)确保工业应用程序的供应链安全、可靠。 第五,数据安全。工业数据的安全直接关系到工业生产线的稳定,数据的丢失、篡改等都会影响生产线,对工业数据采取的安全措施有: (1)建立数据安全管理制度,定期备份重要数据; (2)加密数据,从数据储存和数据传输两个环节入手,使用加密算法对数据加密,利用VPN等技术实现传输加密; (3)部署数据防泄密系统,对数据的操作行为进行监控审计; (4)建立数据销毁机制,明确销毁方式和销毁要求; (5)针对工业互联网平台用户的账户信息、鉴别信息、系统信息等要满足个人信息保护规定。 【案例研究篇】 一、工业互联网典型安全风险 二、安全防护案例 三、工业互联网安全防护技术应用(总结) (1)边界安全 边界安全通常是通过在关键网络节点处部署工控防火墙、网闸、网关等安全隔离设备,比如利用防火墙或者在路由器上设置访问控制列表进行子网间的访问控制和数据隔离,并且,还可增加用户身份认证系统和用户权限管理系统,限制非法的用户访问,确保用户真实性,合法记录用户对网络资源的访问日志,便于后续审计追溯。 (2)接入控制 1)通过堡垒机等装置实现网络的接入管理,包括网络边界识别和资产识别、自动识别在线终端、智能识别终端类型等; 2)对入网终端设备进行身份鉴别和合规验证、展示与交换机端口的映射关系; 3)IP实名制登记和入网终端网络信息生命周期管理,准确识别违规接入和修改IP、MAC等行为。 (3)安全审计 通常部署安全监测审计系统,很多做工控安全的厂家都有,目的是实现网络流量监测与告警,采用被动方式从网络采集数据包,通过解析工控网络流量、深度分析工控协议、与系统内置的协议特征库和设备对象进行智能匹配,实现实时流量监测及异常活动告警,实时掌握工控网络运行状况,发现潜在的网络安全问题。通过设定状态白名单基线,当有未知设备接入网络或网络故障时,可触发实时告警信息。 (4)安全态势感知 通过采集并存储网络环境的资产、运行状态、漏洞收集、安全配置、日志、流量信息、情报信息等安全相关的数据,利用态势预测模型分析并计算安全态势,达到对全局网络空间的不间断监控,发现和挖掘网络中的异常攻击和威胁事件;部署态势感知的话选择大厂的好处是威胁情报渠道广、自身有依托平台等。选择态势感知的两个技术指标分别是: 1)具备针对威胁或者攻击的调查分析及可视化功能,可以对威胁或者攻击相关的攻击路径、攻击目标、采用的手段和影响范围进行快速定位,从而可以快速有效地进行自动化的安全决策支持和响应; 2)具备安全预警机制。 当然,并不完全,从第二章的案例中可以看出针对不同的行业,有不同的解决方案,在产品和服务的选择上是基于自身业务属性和存在的安全风险来考虑,从而选择最优,但是,都存在了一些共性的安全问题。

优秀的个人博客,低调大师

前端学习笔记(3) - JavaScript对象分类

JavaScript中的对象分类 宿主对象(host Objects):由 JavaScript 宿主环境提供的对象,它们的行为完全由宿主环境决定。 内置对象(Built-in Objects):由 JavaScript 语言提供的对象。 固有对象(Intrinsic Objects ):由标准规定,随着 JavaScript 运行时创建而自动创建的对象实例。 原生对象(Native Objects):可以由用户通过 Array、RegExp 等内置构造器或者特殊语法创建的对象。 普通对象(Ordinary Objects):由{}语法、Object 构造器或者 class 关键字定义类创建的对象,它能够被原型继承。 函数对象与构造器对象 JavaScript中使用对象来模拟函数与构造器。JavaScript 为这一类对象预留了私有字段机制,并规定了抽象的函数对象与构造器对象的概念。 函数对象的定义是:具有 [[call]] 私有字段的对象,构造器对象的定义是:具有私有字段 [[construct]] 的对象。我们可以这样说,任何对象只需要实现 [[call]],它就是一个函数对象,可以去作为函数被调用。而如果它能实现 [[construct]],它就是一个构造器对象,可以作为构造器被调用。 程序员使用function关键字创建出来的对象同时拥有[[call]]、[[construct]]属性,所以既可以被当做函数调用也可以当做构造器,只不过它们的行为总是相似的。当返回值为对象时函数对象与构造器对象的作用是相同的。当作为构造器对象使用时过程如下: 以 Object.protoype 为原型创建一个新对象; 以新对象为 this,执行函数的 [[call]]; 如果 [[call]] 的返回值是对象,那么,返回这个对象,否则返回第一步创建的新对象。 es6中的=>函数只能被当做函数调用。

优秀的个人博客,低调大师

前端学习笔记(2) - JavaScript面向对象

javaScript是不是面向对象语言? JavaScript(es6之前)有对象的概念,却没有类的概念,JavaScript对象可以任意添加属性,而java、c++等其他语言却不能。以至于有些人认为JavaScript并非是面向对象的语言,而是基于对象的语言。 实际上JavaScript无疑是面向对象的语言,只不多例如java、c++等语言才用的是“类”的方式来描述对象,这也是最为成功的描述对象方式。但是javaScript采用的较为冷的原型来描述对象的方式。但是由于某些原因JavaScript在原型运行时的基础上加入了例如new、this等语言特性使其看起来更像java。 基于原型的面向对象 “基于类”的编程提倡使用一个关注分类和类之间关系开发模型。在这类语言中,总是先有类,再从类去实例化一个对象。类与类之间又可能会形成继承、组合等关系。类又往往与语言的类型系统整合,形成一定编译时的能力。 “基于原型”的编程看起来更为提倡程序员去关注一系列对象实例的行为,而后才去关心如何将这些对象,划分到最近的使用方式相似的原型对象,而不是将它们分成类。基于原型的面向对象系统通过“复制”的方式来创建新对象。一些语言的实现中,还允许复制一个空对象。这实际上就是创建一个全新的对象。JavaScript的原型对象实现方式并不是真的去复制一个对象,而是使新对象持有一个原型对象的引用。 JavaScript的原型系统其实概括起来如下: 如果所有对象都有私有字段 [[prototype]],就是对象的原型; 读一个属性,如果对象本身没有,则会继续访问对象的原型,直到原型为空或者找到为止。 这个模型在 ES 的各个历史版本中并没有很大改变,但从 ES6 以来,JavaScript 提供了一系列内置函数,以便更为直接地访问操纵原型。三个方法分别为: Object.create 根据指定的原型创建新对象,原型可以是 null; Object.getPrototypeOf 获得一个对象的原型; Object.setPrototypeOf 设置一个对象的原型。 基于类的面向对象 在es6的新语法中引入了class关键字,并从标准中删除了所有与[[class]]相关的私有属性,new与function的怪异搭配终于可以退休了。基于类的面向对象正式成为JavaScript官方的编程范式。(JavaScript中基于类的面向对象编程实际上是基于原型面向对象编程的语法糖) class Animal { constructor(name) { this.name = name; } speak() { console.log(this.name + ' makes a noise.'); } } class Dog extends Animal { constructor(name) { super(name); // call the super class constructor and pass in the name parameter } speak() { console.log(this.name + ' barks.'); } } let d = new Dog('Mitzie'); d.speak(); // Mitzie barks.

优秀的个人博客,低调大师

Python零基础学习笔记(一)

Python是一种解释型、面相对象、动态数据类型的高级程序设计语言。解释型:没有编译环节交互式:可以在一个python提示符,直接互动执行程序面向对象:支持面向对象的风格或代码封装在对象的编程技术初学者的语言:对初级程序员来说,支持广泛的应用程序开发,从简单的文字处理到www浏览器再到游戏都可以写。 特点: 易于学习:相对较少的关键字,结构简单,明确定义的语法 易于阅读:代码定义更为清晰 易于维护:成功点在于源码相当容易维护 一个广泛的标准库:有丰富的库,跨频台兼容性好unix/windows/macintosh 互动模式: 可移植:基于其开源代码的特性 可扩展:可以在python中调用c和c++语言 数据库:python提供所有主要商业数据库的接口 GUI编程:支持GUI,可以创建和移植到很多系统调用 可嵌入:可以将python嵌入到c/c++程序中 缺点: 运行速度慢 代码不能加密

优秀的个人博客,低调大师

ElasticSearch学习笔记1-修改文档

本文中所有用[]括起来的和xxx都是变量 基本操作:1、根据id修改文档,使用POST请求 POST /[index]/[type]/[id]/_update { "doc": {"[XXX]":"[xxxxx]"} } 举例: 上面这个图片中index为test,type为doc,id为1,我们将里面的name改为“name03” age改为20,请求如下: POST /test/doc/_update { "doc": { "name": "name03", "age": 20 } } 返回结果为: { "_index": "test", "_type": "doc", "_id": "1", "_version": 13, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 13, "_primary_term": 1 } 对该id再进行一次查询,结果如图所示: 2、使用脚本修改 POST /[index]/[type]/[id]/_update { "script" : "ctx._source.[xxx] = [xxx]" } 继续使用上面的文档 POST /test/doc/1/_update { "script":"ctx._source.age+=5;ctx._source.name=\"name04\"" } 查询结果:修改成功。3、删除 DELETE /[index]/[type]/[id] 比较简单,不做举例4、批量创建批量创建和批量修改的请求都是一样的, 传的参数不一样请求: POST /[index]/[type]/_bulk 批量创建参数:{"index":{"_id":"xxx"}}{"xxx": "xxx" }{"index":{"_id":"xxx"}}{"xxx": "xxx" } 举例: POST /test01/doc01/_bulk {"index":{"_id":"1"}} {"name": "name01" } {"index":{"_id":"2"}} {"name": "name02","age":20 } {"index":{"_id":"3"}} {"name": "name03","age":20 } --------------1 这里有一点要注意:在图中1的位置,后面一定要换行,否则会报错,提示需要新的一行作为结束的标识,报错信息如下 { "error": { "root_cause": [ { "type": "illegal_argument_exception", "reason": "The bulk request must be terminated by a newline [\n]" } ], "type": "illegal_argument_exception", "reason": "The bulk request must be terminated by a newline [\n]" }, "status": 400 } 注意上面两张图片中最左边序号的不同,下面是正确的json数据,体会什么叫以新的一行作为结束的标识。 这种操作实际上是id存在就更新,不存在就创建,返回结果如下: { "took": 162, "errors": false, "items": [ { "index": { "_index": "test01", "_type": "doc01", "_id": "1", "_version": 6, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 5, "_primary_term": 1, "status": 200 } }, { "index": { "_index": "test01", "_type": "doc01", "_id": "2", "_version": 2, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 1, "_primary_term": 1, "status": 200 } }, { "index": { "_index": "test01", "_type": "doc01", "_id": "3", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 0, "_primary_term": 1, "status": 201 } } ] } 查看下这三个id的具体内容: 5、批量修改参数: {"update":{"_id":"xxx"}} {"doc": { "XXX": "xxx" } } {"delete":{"_id":"xxx"}} 现在对上面创建的三条记录做批量修改: POST /test01/doc01/_bulk {"update":{"_id":"1"}} {"doc": { "name": "name011"}} {"delete":{"_id":"2"}} {"update":{"_id":"3"}} {"script": "ctx._source.age+=5;ctx._source.name=\"name033\""} -----------1 和批量创建一样,最后一行需要换行。查询索引test01的数据如下:数据全部修改成功!

优秀的个人博客,低调大师

【学习笔记】hive 之行拆列explode

1、explode explode(ARRAY) 列表中的每个元素生成一行explode(MAP) map中每个key-value对,生成一行,key为一列,value为一列限制:1、No other expressions are allowed in SELECT SELECT pageid, explode(adid_list) AS myCol... is not supported 2、UDTF's can't be nested SELECT explode(explode(adid_list)) AS myCol... is not supported 3、GROUP BY / CLUSTER BY / DISTRIBUTE BY / SORT BY is not supported SELECT explode(adid_list) AS myCol ... GROUP BY myCol is not supported 2、lateral view 可使用lateral view解除以上限制,语法: lateralView: LATERAL VIEW explode(expression) tableAlias AS columnAlias (',' columnAlias)*fromClause: FROM baseTable (lateralView)* 案例: table名称为pageAds SELECT pageid, adid FROM pageAds LATERAL VIEW explode(adid_list) adTable AS adid; 输出结果: 3、多个lateral view from语句后面可以带多个lateral view语句 案例: 表名:baseTable from后只有一个lateral view: SELECT myCol1, col2 FROM baseTable LATERAL VIEW explode(col1) myTable1 AS myCol1; 结果: 多个lateral view: SELECT myCol1, myCol2 FROM baseTable LATERAL VIEW explode(col1) myTable1 AS myCol1 LATERAL VIEW explode(col2) myTable2 AS myCol2; 结果: 4、Outer Lateral Views 如果array类型的字段为空,但依然需返回记录,可使用outer关键词。 比如:select * from src LATERAL VIEW explode(array()) C AS a limit 10; 这条语句中的array字段是个空列表,这条语句不管src表中是否有记录,结果都是空的。 而:select * from src LATERAL VIEW OUTER explode(array()) C AS a limit 10; 结果中的记录数为src表的记录数,只是a字段为NULL。 比如: 238 val_238 NULL86 val_86 NULL311 val_311 NULL27 val_27 NULL165 val_165 NULL409 val_409 NULL255 val_255 NULL278 val_278 NULL98 val_98 NULL 官方文档: https://cwiki.apache.org/confluence/display/Hive/LanguageManual+LateralView https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF#LanguageManualUDF-explode

优秀的个人博客,低调大师

机器学习笔记——特征标准化

数据标准化是在特征处理环节必不可少的重要步骤。 数据标准化是为了消除不同指标量纲的影响,方便指标之间的可比性,量纲差异会影响某些模型中距离计算的结果。 常见标准化方法主要有归一化、正态化。 数据归一化也即0-1标准化,又称最大值-最小值标准化,核心要义是将原始指标缩放到0~1之间的区间内。相当于对原变量做了一次线性变化。 其公式为 EX = (x- min)/(max - min) 另一种常用的标准化方法是z-score标准化,将原始指标标准化为均值为0,标准化为1的正态分布。 EX = (x - mean)/σ R语言中的特征标准化: library("caTools") library("scales") data(iris) split = sample.split(iris$Species,SplitRatio = .8) train_data = subset(iris,split == TRUE) test_data = subset(iris,split == FALSE) train_data[,-5] = apply(train_data[,-5],2,rescale,to = c(0,1)) test_data[,-5] = apply(test_data[,-5],2,rescale,to = c(0,1)) 以上scales包中的rescale函数可以自动完成指标中0-1标准化的任务,事实上,它可以将原始指标线性变化到任何一个数字区间内。 我们可以来验证结果是否是可信的。 range(train_data[,1]) range(apply(train_data[,-5],2,rescale,to = c(0,1))[,1]) [1] 4.3 7.7 [1] 0 1 当然你也可以自己写一个叫简单的0-1标准化函数 scale1 = function(x){ (x - min(x))/(max(x) - min(x)) } range(apply(train_data[,-5],2,scale1)[,1]) [1] 0 1 z-score标准化 z-score标准化可以通过scale函数快速实现。 train_data[,-5] = scale(train_data[,-5]) mean(train_data[,1]);sd(train_data[,1]) [1] 5.869167 [1] 0.8259241 mean(scale(train_data[,-5])[,1]);sd(scale(train_data[,-5])[,1]) [1] 0 [1] 1 #自定义一个z-score标准化函数 z_norm = function(x){ (x - mean(x))/sd(x) } mean(apply(train_data[,-5],2,z_norm)[,1]);sd(apply(train_data[,-5],2,z_norm)[,1]) [1] 0 [1] 1 Python中sk-learn库中有专门用于处理以上两种标准化的函数。 from sklearn import preprocessing from sklearn.model_selection import train_test_split from sklearn.datasets import load_iris import pandas as pdimport numpy as np iris = load_iris() data = iris['data'] iris_data = pd.DataFrame( data = data, columns = ['sepal_length','sepal_width','petal_length','petal_width'] ) iris_data["Species"] = iris[ 'target'] iris_data["Species"] = iris_data["Species"].map({0:"setosa",1:"versicolor",2:"virginica"}) x,y = iris_data.iloc[:,0:-1],iris_data.iloc[:,-1] train_data,_data,train_target,test_target = train_test_split(x,y,test_size = 0.2,stratify = y) Python中的0-1标准化 min_max_scaler = preprocessing.MinMaxScaler() #实例化0-1标准化方法 X_train_minmax = min_max_scaler.fit_transform(test_data.iloc[:,0:4].values) X_test_minmax = min_max_scaler.transform(test_data.iloc[:,0:4].values) X_train_minmax[:,0].max() - X_train_minmax[:,0].min()1.0 Python中的z-score标准化 训练集第一列的均值和方差如下 train_data.iloc[:,0].mean();train_data.iloc[:,0].std() 5.86166666666666 40.8416853174847874 sc_X = preprocessing.StandardScaler() #实例化z-score标准化方法 X_train = sc_X.fit_transform(train_data.iloc[:,0:4].values) X_test = sc_X.transform(test_data.iloc[:,0:4].values) 标准化后第一列的均值和方差 X_train[:,0].mean();X_train[:,0].std() -2.2907601741432396e-151.0 以上仅介绍了最常用的两种标准化特征的方法及其实现,标准化的方法还有很多,对于什么的模型需要使用标准化以及适用什么方法的标准化,需要视具体场景和数据量级差异而定,小编也在摸索中。 标准化一方面可以防止原始特征中量纲差异影响距离运算(比如欧氏距离的运算)。 另一方面标准化也可以在一定程度上提升算法求解的效率。 原文发布时间为:2018-09-23 本文作者:杜雨 本文来自云栖社区合作伙伴“数据小魔方”,了解相关信息可以关注“数据小魔方”。

优秀的个人博客,低调大师

Android笔记(二) | Activity的启动模式

启动模式 在这里,首先要提到一个名词——任务栈(Task),数据结构中的栈我们都很熟悉,而Android系统采用栈的结构来管理应用程序运行过程中所启动的Activity,即任务栈。知道这一点,对于我们理解启动模式已经足够了。 standard(标准模式):系统的默认启动模式,每次启动一个Activity,都会重新创建一个实例,无论这个实例是否已经被创建。 通常,当我们使用显式Intent启动一个standard模式的Activity时: Intent intent = new Intent(MainActivity.this, NextActivty.class); startActivity(intent); NextActivity会进入MainActivity所在的栈中,即被启动的Activity会进入启动它的那个Activity所在的任务栈中。 这是一种典型的多实例模式,一个任务栈中可以有多个实例,每个实例也可以属于不同的任务栈。 注意:当我们用ApplicationContext启动一个standard模式的Activity时会报错,这是因为standard模式的Activity会默认进入启动它的Activity所属的任务栈中,但是非Activity类型的Context(如:ApplicationContext)没有所谓的任务栈。 singleTop(栈顶复用模式):在这种模式下,如果新Activity位于任务栈栈顶,就不会重新创建,而是回调它的 onNewIntent 方法;如果新Activity已经存在但不是位于栈顶,仍会重新创建新Activity。 例如:假设目前栈内情况为ABCD(D为栈顶),这时要再次启动D,如果D是singleTop模式,栈内情况不变;如果D是standard模式,栈内情况就会变为ABCDD。 singleTask(栈内复用模式):在这种模式下,只要Activity在一个栈中存在,多次启动这个Activity都不会重新创建实例,而是将这个Activity上面的Activity全部出栈,直到这个Activity位于栈顶;并且系统也会回调它的 onNewIntent 方法。 这是一种单实例模式,在一个任务栈中,一个Activity只会存在一个实例。 举例: 假设当前任务栈S1中的情况为ABCD,这时ActivityA以singleTask模式请求启动,其所需要的任务栈为S2,系统就会创建任务栈S2,然后创建A的实例入栈S2,任务栈S1不变。 假设A所需的任务栈为S1,其余情况同上,那么系统就会将BCD全部出栈,然后调用A的 onNewIntent 方法,这时任务栈S1内情况为A。 singleInstance(单实例模式):这种模式在singleTask模式的基础上,要求通过这种模式创建的Activity只能单独位于一个任务栈中,并且这个任务栈中只允许有一个实例存在。 上面是关于四种启动模式的概述,接下来再说明一些特殊情况: 假设目前有两个任务栈,前台任务栈的情况是AB,后台任务栈的情况是CD,假设CD的启动模式均为singleTask。现在请求启动C,由于后台任务栈中C位于栈底,所以C上面的Activity会被出栈,这时前台任务栈的情况为C,后台任务栈的情况为AB(过程见下图1.1)。 图1.1 如果上面请求启动D,那么整个后台任务栈会切换到前台,前台任务栈会被切换到后台(过程见下图1.2)。 图1.2 补充: 为Activity指定所需任务栈的方式: 在AndroidMenifest文件下,对应的activity标签内,有一个TaskAffinity属性,在默认情况下(即不指定TaskAffinity属性值),所有activity所需任务栈的名字为应用的包名。若我们要为某个Activity指定所需任务栈,只需指定TaskAffinity属性值和包名不同即可,这个值会作为这个Activity所在任务栈的名字,当然,这个Activity的启动模式为singleTask时才有意义。 <activity android:name=".SecondActivity" android:launchMode="singleTask" android:taskAffinity="com.example.laughter.task_1"/> 为Activity指定启动模式的方式: 在AndroidManifest文件中指定 launchMode 属性值。 <activity android:name=".SecondActivity" android:launchMode="singleTask" android:taskAffinity="com.example.laughter.task_1"/> 通过在Intent中设置标志位来指定启动模式。(优先级高于第一种,两种方式同时存在时,以第二种为准。) Intent intent = new Intent(MainActivity.this, SecondActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); Activity的常见Flags(标志位) Activity的Flags有很多,有的可以设定Activity的启动模式,有的可以影响Activity的运行状态,在使用时需要注意有些标志位是系统内部使用的,应用程序不需要去手动设置这些标志位以防出现问题。 FLAG_ACTIVITY_NEW_TASK 为Activity指定“singleTask”启动模式 FLAG_ACTIVITY_SINGLE_TOP 为Activity指定“singleTop”启动模式 FLAG_ACTIVITY_CLEAR_TOP 具有此标志位的Activity,当它启动时,在同一个任务栈中所有位于它上面的Activity都要出栈。若该Activity为standard启动模式,那么它自身也会出栈,系统会重新创建这个Activity的实例放入栈顶。根据前面的内容可知,singleTask启动模式默认具有此标记位的效果。

优秀的个人博客,低调大师

(三)Java并发学习笔记--线程封闭

线程封闭 实现好的并发是一件困难的事情,所以很多时候我们都想躲避并发。避免并发最简单的方法就是线程封闭。什么是线程封闭呢? 就是把对象封装到一个线程里,只有这一个线程能看到此对象。那么这个对象就算不是线程安全的也不会出现任何安全问题。实现线程封闭有哪些方法呢? 1. ad-hoc线程封闭 这是完全靠实现者控制的线程封闭,他的线程封闭完全靠实现者实现。也是最糟糕的一种线程封闭。所以我们直接把他忽略掉吧。 2. 栈封闭 栈封闭是我们编程当中遇到的最多的线程封闭。什么是栈封闭呢?简单的说就是局部变量。多个线程访问一个方法,此方法中的局部变量都会被拷贝一分儿到线程栈中。所以局部变量是不被多个线程所共享的,也就不会出现并发问题。所以能用局部变量就别用全局的变量,全局变量容易引起并发问题。 3. ThreadLocal封闭 使用ThreadLocal是实现线程封闭的最好方法,有兴趣的朋友可以研究一下ThreadLocal的源码,其实ThreadLocal内部维护了一个Map,Map的key是每个线程的名称,而Map的值就是我们要封闭的对象。每个线程中的对象都对应着Map中一个值,也就是ThreadLocal利用Map实现了对象的线程封闭。这里就不说ThreadLocal的使用方法了,度娘一下便知。 总之,当我们要用线程封闭来避免并发问题的时候,最好使用的就是 【栈封闭】 和 【ThreadLocal】。

优秀的个人博客,低调大师

Java中4种引用类型笔记

强引用(Strong Reference) 强引用就是我们经常使用的引用,其写法如下: Object o=new Object(); // 强引用 当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。如果不使用时,要通过如下方式来弱化引用,如下: o=null; // 帮助垃圾收集器回收此对象 显式地设置o为null,或超出对象的生命周期范围,则gc认为该对象不存在引用,这时就可以回收这个对象。具体什么时候收集这要取决于gc的算法。 public void test(){ StringBuilder str=new StringBuilder(); // 省略其他操作 } 在一个方法的内部有一个强引用,这个引用保存在栈中,而真正的引用内容(StringBuilder)保存在堆中。当这个方法运行完成后就会退出方法栈,则引用内容的引用不存在,这个StringBuilder会被回收。 但是如果这个str是全局的变量时,就需要在不用这个对象时赋值为null,因为强引用不会被垃圾回收。 强引用在实际中有非常重要的用处,举个ArrayList的实现源代码: private transient Object[] elementData; public void clear() { modCount++; // Let gc do its work for (int i = 0; i < size; i++) elementData[i] = null; size = 0; } 在ArrayList类中定义了一个私有的变量elementData数组,在调用方法清空数组时可以看到为每个数组内容赋值为null。不同于elementData=null,强引用仍然存在,避免在后续调用 add()等方法添加元素时进行重新的内存分配。使用如clear()方法中释放内存的方法对数组中存放的引用类型特别适用,这样就可以及时释放内存。 软引用(SoftReference) 如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。 String str=new String("abc"); // 强引用 SoftReference<String> softRef=new SoftReference<String>(str); // 软引用当内存不足时,等价于: If(JVM.内存不足()) { str = null; // 转换为软引用 System.gc(); // 垃圾回收器进行回收 } 软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。 弱引用(Weak Reference) 弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。 弱引用简单来说就是将对象留在内存的能力不是那么强的引用。使用WeakReference,垃圾回收器会帮你来决定引用的对象何时回收并且将对象从内存移除。创建弱引用如下: WeakReference<Widget> weakWidget = new WeakReference<Widget>(widget); 使用weakWidget.get()就可以得到真实的Widget对象,因为弱引用不能阻挡垃圾回收器对其回收,你会发现(当没有任何强引用到widget对象时)使用get时突然返回null。 解决上述的widget序列数记录的问题,最简单的办法就是使用Java内置的WeakHashMap类。WeakHashMap和HashMap几乎一样,唯一的区别就是它的键(不是值!!!)使用WeakReference引用。当WeakHashMap的键标记为垃圾的时候,这个键对应的条目就会自动被移除。这就避免了上面不需要的Widget对象手动删除的问题。使用WeakHashMap可以很便捷地转为HashMap或者Map。 引用队列(Reference Queue) 一旦弱引用对象开始返回null,该弱引用指向的对象就被标记成了垃圾。而这个弱引用对象(非其指向的对象)就没有什么用了。通常这时候需要进行一些清理工作。比如WeakHashMap会在这时候移除没用的条目来避免保存无限制增长的没有意义的弱引用。 引用队列可以很容易地实现跟踪不需要的引用。当你在构造WeakReference时传入一个ReferenceQueue对象,当该引用指向的对象被标记为垃圾的时候,这个引用对象会自动地加入到引用队列里面。接下来,你就可以在固定的周期,处理传入的引用队列,比如做一些清理工作来处理这些没有用的引用对象。 虚引用(PhantomReference) “虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。 虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。 总结 Java4种引用的级别由高到低依次为: 强引用 > 软引用 > 弱引用 > 虚引用 通过图来看一下他们之间在垃圾回收时的区别: 当垃圾回收器回收时,某些对象会被回收,某些不会被回收。垃圾回收器会从根对象Object来标记存活的对象,然后将某些不可达的对象和一些引用的对象进行回收 通过表格来说明一下,如下: 引用类型 被垃圾回收时间 用途 生存时间 强引用 从来不会 对象的一般状态 JVM停止运行时终止 软引用 在内存不足时 对象缓存 内存不足时终止 弱引用 在垃圾回收时 对象缓存 gc运行后终止 虚引用 Unknown Unknown Unknown

优秀的个人博客,低调大师

JSP EL表达式学习笔记

<%@page import="java.util.HashMap"%> <%@page import="java.util.Map"%> <%@page import="java.util.ArrayList"%> <%@page import="java.util.List"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="hah.*" errorPage="common/zz.jsp" %> <%-- errorPage="common/zz.jsp" --%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <% String name1="name1"; int name2=111; int[] a=new int[3]; //int xx=10/0;//错误 //out.write(xx); a[1]=3; Student student=new Student("ss",22); request.setAttribute("name1", name1); session.setAttribute("name2", name2); request.setAttribute("intx", a); session.setAttribute("student",student); List<Student> list=new ArrayList<Student>(); list.add(new Student("11",111)); list.add(new Student("22",222)); list.add(new Student("33",333)); request.setAttribute("listx",list); Map<String,Student> map=new HashMap<String,Student>(); map.put("1", new Student("11",111)); map.put("2", new Student("22",222)); map.put("2", new Student("33",333)); pageContext.setAttribute("mapx",map); %> <%-- 注意 <%@ pageisELIgnored="true" %> 表示是否禁用EL语言,TRUE表示禁止.FALSE表示不禁止.JSP2.0中默认的启用EL语言。 --%> <%=pageContext.findAttribute("name2")%> <%-- 等效于${name2 } --%> <%-- ${name } 等价于 <%=pageContext.findAttribute("name")%> --%> EL表达式: ${name1 } <%-- 从指定的域中获取数据 否则它是按照小到大的顺序查找域对象的 pageScoep / requestScope / sessionScope / applicationScope --%> ${sessionScope.name2 } ${intx[1] } ${student.name } - ${student.age } ${student["name"] } -${student["age"] } <br/><!-- 这个比上面那个好 --> <%-- (点相对于调用getXX()方法) <%=((Student)pageContext.findAttribute("student")).getName()%> --%> ${listx[2]["name"] } - ${listx[2].age } <br/> <% for(int i=0;i<list.size();i++){ %> <%=list.get(i).getName() +" | "+list.get(i).getAge()%> <% } %> <br/> <!-- //里面不能放额外的字符串 --> ${listx[1]["name"] }---${listx[1].age } <%-- listx[0]等价于 (中括号相对于调用get(参数)方法) ((List)pageContext.findAttribute("list")).get(0) --%> <br/> ${mapx['1']["name"] } <br/> <%-- ${3>=2 } ${10!=3 } <br/> ${true||false} --%> <% String haha=""; request.setAttribute("haha", haha); %> 判断null:${haha==null } 判断空字符: ${haha=="" }<br/> 判空:${haha==null||haha=="" } 另一种判空: ${empty haha } </body> </html>

优秀的个人博客,低调大师

spring cloud(学习笔记) Enreka服务治理

服务治理是微服务架构最为核心和基础的模块,主要用来实现各个微服务实例的自动化注册和发现。 记录一下服务注册中心的搭建以及高可用注册中心的实现 1.首先创建两个基础 的spring boot工程,spring boot创建工程的网站:http://start.spring.io/,创建界面如下 2.解压工程,用Maven的形式导入工程(File->new->project from Existing Soures,选择解压工程导入) 3.两个工程中都添加依赖(eureka) 1 <properties> 2 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 3 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> 4 <java.version>1.8</java.version> 5 <spring-cloud.version>Finchley.RELEASE</spring-cloud.version> 6 </properties> 7 8 <dependencies> 9 <dependency> 10 <groupId>org.springframework.boot</groupId> 11 <artifactId>spring-boot-starter-web</artifactId> 12 </dependency> 13 <dependency> 14 <groupId>org.springframework.cloud</groupId> 15 <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> 16 </dependency> 17 18 <dependency> 19 <groupId>org.springframework.boot</groupId> 20 <artifactId>spring-boot-starter-test</artifactId> 21 <scope>test</scope> 22 </dependency> 23 </dependencies> 24 25 <dependencyManagement> 26 <dependencies> 27 <dependency> 28 <groupId>org.springframework.cloud</groupId> 29 <artifactId>spring-cloud-dependencies</artifactId> 30 <version>${spring-cloud.version}</version> 31 <type>pom</type> 32 <scope>import</scope> 33 </dependency> 34 </dependencies> 35 </dependencyManagement> 36 37 <build> 38 <plugins> 39 <plugin> 40 <groupId>org.springframework.boot</groupId> 41 <artifactId>spring-boot-maven-plugin</artifactId> 42 </plugin> 43 </plugins> 44 </build> 4.在注册中心工程配置文件中添加服务 1 server.port=9000 2 3 spring.application.name=eureka-server 4 spring.profiles.active=dev 5 6 eureka.instance.hostname=localhost 7 eureka.client.register-with-eureka=false 8 eureka.client.fetch-registry=false 9 eureka.server.enable-self-preservation=false 不知道这些参数的自己百度 5.在注册中心的入口类中加入注解@EnableEurekaServer 1 package com.example.enrekaserver; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; 6 7 @EnableEurekaServer 8 @SpringBootApplication 9 public class EnrekaServerApplication { 10 public static void main(String[] args) { 11 SpringApplication.run(EnrekaServerApplication.class, args); 12 } 13 } 6.启动注册中心,在浏览器中访问,界面如下 7.在另一个工程中,加入注解 @EnableDiscoveryClient 1 package com.example.demoOne; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 6 7 @EnableDiscoveryClient 8 @SpringBootApplication 9 public class DemoOneApplication { 10 public static void main(String[] args) { 11 SpringApplication.run(DemoOneApplication.class, args); 12 } 13 } 8.配置文件中加入配置,指定服务注册中心 1 spring.application.name=demoOne-service 2 spring.profiles.active=dev 3 eureka.client.service-url.defaultZone=http://localhost:9000/eureka/ 9.我们可以在需要注册是工程里添加一个类作为测试,并打印日志 1 package com.example.demoOne.didispace; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 5 import org.springframework.cloud.client.ServiceInstance; 6 import org.springframework.cloud.client.discovery.DiscoveryClient; 7 import org.springframework.web.bind.annotation.RequestMapping; 8 import org.springframework.web.bind.annotation.RequestMethod; 9 import org.springframework.web.bind.annotation.RestController; 10 11 import java.util.logging.Logger; 12 13 @RestController 14 public class HelloController { 15 private final Logger logger=Logger.getLogger(String.valueOf(getClass())); 16 17 @Autowired 18 private DiscoveryClient client; 19 20 @RequestMapping(value = "/hello",method = RequestMethod.POST) 21 public String index(){ 22 ServiceInstance instance = (ServiceInstance) client.getServices(); 23 logger.info("/hello,host:"+instance.getHost()+",service_id:"+instance.getServiceId()); 24 return "hello world"; 25 } 26 } 10.启动工程,我们可以在服务注册中心看到我们注册的服务 注册中心搭建成功。可以测试一下试试 小舟从此逝,江海寄余生。 --狐狸

资源下载

更多资源
Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册