摘要:本文提出了一种基于深度强化学习(RL)的控制方法,以提高学习效率和效果来解决风电场控制问题。具体地,设计了一种新的复合体验重放(CER)策略,并将其嵌入到深度确定性策略梯度(DDPG)算法中。CER提供了一种新的采样方案,通过在奖励和时间差异(TD)误差之间进行权衡,可以深入挖掘存储变迁的信息。在神经网络的训练过程中引入修正的重要性-采样权重,以解决CER导致的分布不匹配问题。然后,将CER-DDPG方法应用于风电场总发电量优化。
与原始DDPG相比,直接移植PER到DDPG可能不会获得太多(甚至会导致性能下降)。这是因为PER最初是为DQN设计的,其中只有动作状态值函数(即Q函数)是近似的。TD误差直接用于驱动这个近似过程,使其完美地满足优先级的目的。然而,与DQN相比,DDPG有一个额外的actor来生成连续的控制策略。因此,DDPG转换的优先级需要重新设计因为TD误差对actor的重要性是值得怀疑的。
【略去;不在我的研究范围内】
在DDPG框架中引入了一种新的采样策略。我们将其命名为复合经验回放(CER),因为它不仅利用了TD误差的信息,还利用了奖励来对训练批次进行采样,在这里,奖励被用来衡量转换相对于执行器网络的优先级。这种设计基于这样的观察,即执行器网络的更新是由策略梯度算法中的奖励隐式驱动的。
策略梯度算法的早期版本【REINFORCE】直接使用奖励进行训练。CER有能力平衡两组优先级(即TD错误和奖励),在critic和actor的学习之间进行权衡。此外,采用基于复合优先级的修正重要性采样权重(modified importancesampling weights, ISWs)来修正CER中由于分布不匹配引起的偏差。
它包括几部分: DDPG, CER, reward regularization, and the
wind farm
main critic network的更新是由以下损失函数驱动的:
n表示每个训练步骤所选样本的批大小
ωi是第i个样本的重要权值,在CER设计中给出了它的具体表达式
δi为第i个样本的TD误差:
main actor的更新通过policy gradient策略:
需要定义transition的采样优先级。
一方面,TD误差直接参与了critic的损失构建。即可以衡量相应的transition对于critic来说有多“surprise”。
另一方面,行动者受到rewards的隐性驱动。rewards是transition优先级目的的适当选择。
基于以上,在CER中存储了两组优先级:
为了确保PR中的所有优先级都是有效的概率,我们需要将奖励空间从R投影到R+;实现这一目标的一个简单方法是设置:
R可能需要被投影到一个有界的区间:
即,基于projected的奖励,我们将PR中的优先级设计为:
由于transition由两组优先级采样,因此需要解决重复问题。
其中,在小批量B中,li = 1,表示transition只进行PT采样;li = 2表示仅用PR对transition进行采样;最后,li = 3表示同时对transition进行PT和PR采样
基于这些标签,CER确保B中所有的transition都是不同的,无论它们是否在采样过程中重复
偏差修正:期望值的估计依赖于与期望相同的分布对应的更新。CER和其他优先级抽样策略(例如PER)改变了这种分布
ISWs可用于CER中,以缓解因分布不匹配而导致的潜在估计偏差。与PER不同,CER中的ISWs与相应transition的重复条件有关。
CER实质上通过PT和PR构建了两组平行的transition,即T组和R组,在组T和组R中都没有内部重复。因此,对于只在组T或组R中的transition,它们的isw直接由它们的采样概率决定:
对于T组和R,它们的isw是原始isw的线性组合:
无论在两个组中重复多少次transition,CER都确保最终的minibatch B始终具有固定的大小,并且B中的transition都彼此不同。
对于每次采样:初始化参数为0
采样BT batch:从BT中根据TD-error优先采样[1-a]n个transition,并设置它们的l=1;和w
采样BR batch:进入while循环:直到采样transition的个数满足于B minibatch结束
从buffer里根据rewards采样一个transition:
- 如果这个transition的l=0【说明没有被采样过】,设置其l=2,w,并把它放入BR batch中,其数量+1
- 如果这个transition的l=1【说明被BT采样过】,设置其l=3,调整ISW:w
- 如果这个transition的l=2、3【说明被BR采集过或者BR和BT共享的】,忽略并重新采样
总数量到达采样N,连接BT和BR成为B minibatch
第一话回答得不错,但这不是我想要的答案,回去等通知吧这是一个困扰我司由来已久的问题,近年来随着我司业务的急遽发展,单表数据量越来越大,这样会导致读写性能急遽下降,自然而然的我们想到了分库分表,不过众所周知分库分表规则比较复杂,而且业务代码可能需要大改(由于数据分布在不同的库表里,业务需要判断到底去哪些表取数,并且取完后需要将数据再聚合在一起返回前端),所以经过横向对比我们采用了阿里开源的分库分表中间件Cobar,这样的话一来Cobar根据我们设定的规则分库分表了,二来原来调用SQL的地方只需改成调用Cobar即可,Cobar会自动根据我们写的SQL去各个分库分表里查询并将结果返回给我们,我们业务层的代码几乎不需要改动(即对应用是透明的)如图示:使用cobar进行分库分表后,可以看到业务代码几乎不需要改动所以问题是?使用Cobar确实解决了分库分表和对业务代码侵入性的问题,但由于又引入了一个中间层,导致可用性降低,为了防止Cobar不可用等造成的影响,我们需要监控Cobar的各项性能指标,如SQL执行时间,是否失败,返回行数等,这样方便我们分析Cobar的各项指标,这就是我们常说的SQL
今天在朋友的群辉上,又设置了一次增加dnspod自定义解析,开始的时候,只记得需要手动修改一个ddns相关的文件,但是不记得这个文件的具体位置了!找了很久才找到,在此,做一个记录,同时也希望我的方法对大家有所帮助!我们看下面的图片通过winscp登录群辉,然后进入etc目录, 这时候我们向下拉滚动条,可以看到两个ddns开头的文件,分别是ddns.conf和ddns_provider.conf,这里的ddns_provider.conf文件,就是我们为了增加dnspod的自定义ddns解析要修改的文件。因为原本群辉的外部访问里,默认只有一个dnspod.cn的ddns解析接口,这样,当我们需要用到多个域名在群晖上进行ddns动态解析的时候,就不够用了(dnspod.cn的接口用一个就再没有了),这就需要,我们手动增加dnspod.cn的解析接口,从而使我们可以使用多个域名同时进行利用dnspod.cn进行ddns的动态解析!下面我们打开ddns_provider.conf这个文件,注意,我是使用的emedit对此文件进行编辑的!我们可以看到ddns_provider.conf文件中包含
本文原题“百度直播消息服务架构实践”,由百度APP消息中台团队原创分享于“百度Geek说”公众号,为了让文章内容更通俗易懂,本次已做排版优化和内容重新划分,原文链接在文末。1、引言一套完整的直播系统核心功能有两个:1)实时音视频的推拉流;2)直播间消息流的收发(包括聊天消息、弹幕、指令等)。本文主要分享的是百度直播的消息系统的架构设计实践和演进过程。实际上:直播间内用户的聊天互动,虽然形式上是常见的IM聊天消息流,但直播消息流不仅仅是用户聊天。除用户聊天外:直播间内常见的用户送礼物、进场、点赞、去购买、主播推荐商品、申请连麦等互动行为的实时提醒,也是通过消息流下发的。此外:直播间关闭、直播流切换等特殊场景,也依赖消息流的实时下发。所以,直播系统内的消息流可以认为是直播间内主播与用户间实时互动和直播间实时控制的基础能力,也是系统支撑。如果说实时音视频推拉流是直播系统的灵魂,那消息流可以说是直播系统的骨架,它的重要性不言而喻。那么,如何构建直播的消息系统,又有哪些挑战需要解决,借着本文我们一起来梳理一下。(本文同步发布于:http://www.52im.net/thread-3515-1-
文章目录引入话题为什么需要k8s?应用部署模式的演进管理大量的容器带来了新的挑战k8s的集群架构pod——k8s调度的最小单元了解pod引入话题平台实现异构 比如你用k8s要实现异构,其实只要通信协议能跨平台就0K了,因为平台带了服务发现,负载均衡,容错限流等等,不过平台也有局限性,就比如一个大型的遗留系统,一部分在K8s内,一部分使用传统模式部署你就得郁闷,或者得把两块分割开,走网关。所以回到你的问题,最佳实践我觉得没有,三种玩法都有自己的特色,也有自己的局限性,还是得根据你的实际项目,合理取舍,架构设计很多时候其实就是在做取舍。为什么需要k8s?容器编排调度引擎——k8s的好处应用部署模式的演进虚拟化模式 容器化模式 相比虚拟机和容器容器更加轻量级,启动更快(秒级) 容器可移植性更好管理大量的容器带来了新的挑战容器编排调度引擎——k8s的好处简化应用部署 提高硬件资源利用率 健康检查和自修复 自动扩容缩容 服务发现和负载均衡k8s的集群架构主节点,承载k8s的控制和管理整个集群系统的控制面板 工作节点,运行用户实际的应用 k8s集群组件pod——k8s调度的最小单元一个pod包
来源:樊亦凡 juejin.im/post/5eb9faa26fb9a0437e0e98991.前言2.认识Optional并使用3.实战场景再现4.Optional使用注意事项5.jdk1.9对Optional优化前言相信不少小伙伴已经被java的NPE(NullPointerException)所谓的空指针异常搞的头昏脑涨,有大佬说过“防止NPE,是程序员的基本修养。”但是修养归修养,也是我们程序员最头疼的问题之一,那么我们今天就要尽可能的利用Java8的新特性Optional来尽量简化代码同时高效处理NPE(NullPointerException空指针异常)2.认识Optional并使用简单来说,Opitonal类就是Java提供的为了解决大家平时判断对象是否为空用会用null!=obj这样的方式存在的判断,从而令人头疼导致NPE(NullPointerException空指针异常),同时Optional的存在可以让代码更加简单,可读性跟高,代码写起来更高效.常规判断://对象人 //属性有name,age Personperson=newPerson(); if(null==
CC主要是用来攻击页面的。大家都有这样的经历,就是在访问论坛时,如果这个论坛比较大,访问的人比较多,打开页面的速度会比较慢,访问的人越多,论坛的页面越多,数据库压力就越大,被访问的频率也越高,占用的系统资源也就相当可观。 一,定义 CC(ChallengeCollapsar,挑战黑洞)攻击是DDoS攻击的一种类型,使用代理服务器向受害服务器发送大量貌似合法的请求。CC根据其工具命名,攻击者使用代理机制,利用众多广泛可用的免费代理服务器发动DDoS攻击。许多免费代理服务器支持匿名模式,这使追踪变得非常困难。 CC攻击的原理就是攻击者控制某些主机不停地发大量数据包给对方服务器造成服务器资源耗尽,一直到宕机崩溃。CC主要是用来攻击页面的,可以归为DDoS攻击的一种,两者之间的原理都是一样的,即发送大量的请求数据来导致服务器拒绝·服务,是一种连接攻击。CC攻击又可分为代理CC攻击和肉鸡CC攻击。代理CC攻击是黑客借助代理服务器生成指向受害主机的合法网页请求,实现DDoS和伪装就叫ChallengeCollapsar。而肉鸡CC攻击是黑客使用CC攻击软件,控制大量肉鸡,发动攻击,相比
1、什么是Spring框架,Spring框架有哪些主要模块Spring框架是一个为Java应用程序开发提供综合、广泛的基础性支持的Java平台。Spring帮助开发者解决了开发中基础性的问题,使得开发人员可以专注于应用程序的开发。Spring框架本身也是按照设计模式精心打造的,这使得我们可以在开发环境中安心地集成Spring框架,不必担心Spring是如何在后台工作的。2、使用Spring框架能带来哪些好处下面列举了一些使用Spring框架带来的主要好处。(1)DependencyInjection(DI)使得构造器和JavaBeanproperties文件中的依赖关系一目了然。(2)与EJB容器相比较,IoC容器更加趋向于轻量级。这样一来使用IoC容器在有限的内存和CPU资源的情况下进行应用程序的开发和发布就变得十分有利。(3)Spring并没有闭门造车,Spring利用了已有的技术,比如ORM框架、logging框架、J2EE、Quartz和JDKTimer,以及其他视图技术。(4)Spring框架是按照模块的形式来组织的。由包和类的编号就可以看出其所属的模块,开发者只需选用需要的
「K8S生态周报」内容主要包含我所接触到的K8S生态相关的每周值得推荐的一些信息。欢迎订阅知乎专栏「k8s生态」。1kind(KubernetesInDocker)v0.4.0正式发布kind(KubernetesInDocker)是我很喜欢并且一直持续参与贡献的项目,本周发布了v0.4.0版本。v0.4.0版本中,默认的Kubernetes版本升级到了v1.15版本,且kind.sigs.k8s.io/v1alpha2版本的API已经过期,请更新使用kind.sigs.k8s.io/v1alpha3。目前暂时移除了使用apt构建Node镜像的选项,之后版本中可能会加回来,直接使用上游构建好的二进制文件进行安装。在此版本中,我们增加了一个nodes[].extraPortMappings的配置,可以直接通过此配置进行端口的转发,以便从宿主机上直接访问到集群上使用NodePort方式部署的服务,这样更容易模拟真实的网络环境,否则只能通过其他的转发或者网络代理的方式来进行通信了。同样的,紧跟着上游的开放,这个版本中也增加了对IPv6的支持,可以直接通过networking.ipFamily
在python标准库中,并没有直接操作Excel模块,需要借助第三方模块xlrd模块负责从Excel中读取数据xlwt则是将数据写入到Excel中去这里需要用到xlwt模块,从第三方库中安装xlwt模块很简单,一条命令足以pip3installxlwt先写一个简单的python程序测试一下,创建一个名为excelwrite.py文件,代码如下:# 导入xlwt模块 import xlwt if __name__ == '__main__': # 创建一个Workbook对象book, book = xlwt.Workbook(encoding='utf8', style_compression=0) # 创建一个sheet对象,并添加表名为dede # 一个excel可以有多个表,每个表都有对应的表名 sheet = book.add_sheet('dede') # 向dede表中添加数据 sheet.write(0, 0, 'hstking'
必读: Android12(S)图像显示系统-开篇 前言 Android源码中有包含drm_hwcomposer:/external/drm_hwcomposer/ drm_hwcomposer这个过程下的代码架构变化还是很频繁的,我这里分析直接去drm_hwcomposer的官方地址抓取最新的code来做分析了 解析 这个工程编译后会产生sharedlibrary:/vendor/lib/hw/hwcomposer.drm.so drm_hwcomposer作为一个HALmodule,其写作实现还是遵循了旧有的AndroidHALModule的接口实现规则。 看看一些结构体的定义以及他们之间的关系: 结构体hw_device_t的定义 [/hardware/libhardware/include/hardware/hardware.h] typedefstructhw_device_t{ tag;/**tagmustbeinitializedtoHARDWARE_DEVICE_TAG*/ uint32_tversion; structhw
问题参考:关于用DLL接中使用std::vector之后出现的问题 以前也知道有这么个问题,公司有个项目用到dll,已经定好用vector了(不是我定的,我一直都是用struct*的参数)。 在dll函数中用到了push_back,在主程序中之前用一个全局(跟随对话框类)变量,倒没啥问题。 这次在函数new新对象时,每次函数结束后会自动调用析构函数,就会中断到释放vector资源这里。 解决方法是,将在dll中push_back的vector从类中拿出来(就不会被自动析构了),定义到全局中,或者设置为static。 注:如果设置static,除了头文件中的声明,还需要在实现中再定义一次,vector<SProperty>Parse::navData; 调试DLL时还需要注意的其他问题: Release版本对应Releasedll;Debug对应Debugdll,不能错开调用。 dll生成的平台工具集要统一,我就遇到很多莫名奇妙的内存错误(创建和释放都有)【当时环境是:dll使用VS2010(v100),主程序使用VS2012(v110)】,统一改为vs2010就没有那些
软件测试是程序的一种执行过程,目的是尽可能发现并改正被测试软件中的错误,提高软件的可靠性,是软件生命周期中一项非常重要的工作。 在软件测试中,可以采用纯手工方式,但是手工测试方法存在一些典型的缺陷:昂贵且复杂、需要大的人员和设备;可重复性有限;无法覆盖式所有代码路径;许多与死锁、资源冲突、多线程有关的错误很难捕捉到,特别是当大量测试用例需要在短时间内完成时,若没有大量人力资源,手动测试无法开展。 由于手工测试存在的局限性,自动化测试应运而生。自动化测试就是通过自动化测试工具或其他手段,按照测试人员的预定计划进行自动的测试,目的是减轻手工测试的劳动量,从而达到提高软件质量的目的。目前,软件测试借助测试工具已经成为必要,并向全面自动化发展,以解决手工测试的局限性,带来最大收益。 ***测试工具的选择** 面对目前众多的测试工具,我们在对其进行分析和评估时,应注重其特性,针对测试的实际需求,可以着重从以下几点入手,选择测试工具并非测试功能越强大越好,因为解决问题是前提,适用才是根本。 首先,测试工具要具有跨平台和对环境的兼容性,能够支持不同的运行平台,如各种操作系统和浏览器。 其次,操作界
Japanese-邮件写作场景例4-确认资料中记录错误和笔误 件名:講演会パンフレット原稿についての確認 ○○○○様 いつもお世話になっております。 早速ですが、先日いただいた講演会のパンフレット原稿の記載内容について、①いくつか確認させていただきたい点がございます。 講演者氏名が「本村」様になっておりますが、講演されるのは確か「木村」様②ではなかったでしょうか。 また、講演会開始時刻が午後1時とありますが、午後1時半開始③とお聞きしていたように思います。 ④こちらの認識違いかもしれませんが、念のためお伺いいたします。 (後略) どうぞよろしくお願い致します。 ○○○ アマゾンジャパン合同会社 Point①:如果有多个需要确认的内容,要加上「いくつか」。 Point②:向 对方确认自己记录的内容时,可以用「~ではなかったでしょうか」这样的句式,没有直接否定对方,因此不会显得失礼。 Point③:这个也是向对方传达自己听到并记得的内容时,不失礼的表达方式。 Point④:不要让对方感觉你在指责他的错误。加上含有「自分が間違っているかもしれない」这样的铺垫语会比较好。
打算从0到1,重新做一遍DWVA靶场,复习各个技巧并记录下思路和总结。 第三轮 爆破已经失效,返回结果全部都是302 这个没得法,将username和password分别使用万能密码sqlfuzz一遍,还是无果..... 打开源码分析, 发现没啥特殊的,只是对username和password进行了一次stripslashes过滤,查了下,这是一个过滤\的函数,那么我尝试admin'#绕过 发现也不可以.......问题出现哪里?我填入的admin'#中并没有\之类的反斜杠啊,我决定加入对经过处理后的username和passwrd打印,看看有啥不一样的地方 加了这三个打印,再试试admin'#看看会发生什么....... admin'#变成admin\'#了,将'进行了转义。 首先想到宽字节注入admin%df'or1=1#进行尝试。 很遗憾,还是不行。放弃注入这条路。 看
1.1CiscoPacketTracer CiscoPacketTracer(以下简称PT)是一款由思科公司开发的,为网络课程的初学者提供辅助教学的实验模拟器。使用者可以在该模拟器中搭建各种网络拓扑,实现基本的网络配置。 1.2华为eNSP 华为eNSP是一款由华为公司研发的虚拟仿真软件,主要针对网络路由器、交换机进行软件仿真,支持大型网络模拟,让用户在没有真实设备的情况下,使用模拟器也能制作网络拓扑并进行实验。 ICT一般指信息与通信技术。信息与通信技术(ICT,informationandcommunicationstechnology)是一个涵盖性术语,覆盖了所有通信设备或应用软件以及与之相关的各种服务和应用软件, 1.3H3CH3CCloudLab H3CH3CCloudLab是一款由华三公司研发的网络云平台,模拟真实设备,为用户提供基本的设备信息,并满足初级用户在没有真实设备的条件下进行设备配置的学
1.初步了解web安全链接:http://pan.baidu.com/s/1i4RE1XN密码:op83 2.域名,服务器,网站搭建环境等介绍链接:http://pan.baidu.com/s/1nvhLssp密码:wq1u 3.搭建一个win+iis+accees网站链接:http://pan.baidu.com/s/1bQ6Mse密码:fr1r 4.搭建iis+php+mysql网站链接:http://pan.baidu.com/s/1nvGrpxR密码:hhxm 5.谷歌语法简介链接:http://pan.baidu.com/s/1qYvmw00密码:01g1 6.sql注入挖掘与防御链接:http://pan.baidu.com/s/1qYLAK5u密码:724f 7.xss漏洞挖掘链接:http://pan.baidu.com/s/1i4IRawH密码:9fd4 8认识cms及0day链接:http://pan.baidu.com/s/1i5oFcJr密码:8m6b 9利用注入简单拿shell链接:http://pan.baidu.com/s/1dFNZf3r密码:n8kg
一、命令模式定义 在软件设计系统中,行为的请求者与行为的实现者总是耦合在一起,在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,实现二者之间的松耦合。这就是命令模式。在现实生活中,电视遥控器,我们只需要知道按那个按钮能够打开电视、关闭电视和换台即可,并不需要知道是怎么开电视、关电视和换台的,在这个例子中电视机酒是行为的实现者,而遥控器就是行为的请求者, 命令模式:将请求封装成对象,以便使用不同的请求、日志、队列等来参数化其他对象。命令模式也支持撤销操作。 模式结构 Command:定义命令的接口,声明要执行的方法; ConcreteCommand:命令接口实现的对象,实现了Command接口中的方法,一般是虚实现,调用接收者的功能来完成要执行的操作; Receiver:接收者,命令的真正执行对象; Invoker:命令的请求者,是命令模式中相当重要的角色,通过Invoker来对各个命令进行
一、Web.Config继承特性 首先我们就来看看配置文件的继承层次。都知道在ASP.NET中有很多的配置文件,如machine.config,web.config,特别是web.config出现在很多的地方,出现在不同的地方作用也不一样。而且我们还知道machine.config中的配置对服务器上所有ASP.NET网站起作用,而web.config中的配置就依据它所在的位置而定,如在一个网站根目录中的web.config就对整个网站起作用,在一个网站中的某个文件夹中的web.config就只对该文件夹起作用,而且网站跟目录中的web.config中的配置也对这个文件夹起作用。这就反映出了另外一个事实:配置文件是有继承层次的.换个角度,对于一个网站中的某个文件夹,它不仅仅只是受本文件夹中web.config的配置约束,而且还收到本网站中根目录下的web.config的约束,而且还受到本台服务器上的machine.config的约束。<br/> 下面我们就来具体的看看ASP.NET中的配置文件的继承层次:1.machine.confiig-在ASP.NET中,很多的默认的配置
这个作业属于那个课程 C语言程序设计II 这个作业要求在哪里 第十二周作业要求 我在这个课程的目标是 了解指针与函数的关系,掌握指针作为函数返回值 这个作业在哪个具体方面帮助我实现目标 锻炼了我的编程能力 参考文献 C语言程序设计II第十一章 6-1计算最长的字符串长度(15分) 本题要求实现一个函数,用于计算有n个元素的指针数组s中最长的字符串的长度。 函数接口定义: intmax_len(char*s[],intn); 其中n个字符串存储在s[]中,函数max_len应返回其中最长字符串的长度。 裁判测试程序样例: #include<stdio.h> #include<string.h> #include<stdlib.h> #defineMAXN10 #defineMAXS20 intmax_len(char*s[],intn); intmain() { inti,n; char*string[MAXN]={NULL}; scanf("%d",&n); for(i=0;i<n;i++){ s
OS和裸机的区别 OS即(operatingsystem)操作系统,比如我们常用的windows系统,mac系统,android系统,ios系统,linux系统等,都属于操作系统。操作系统的本质是一个特殊的软件,它直接管理硬件,同时为各个应用程序划分资源(内存,堆栈,时间片等),并提供控制(调度,同步)。不管是计算机还是单片机,在任意时刻都只能运行一段代码,顶多是运行速度上会有差距,为什么我们能够在电脑上打开多个软件同时流畅的使用,就需要归功于操作系统对于软件的控制,操作系统会将各个应用程序抽象成进程,给每个进程独立的分配资源,同时对他们进行调度,使得每一个进程都仿佛是在独占整个计算机。 以下图为例,该图较为清晰的反映了硬件,操作系统和应用程序之间的层次关系。可以发现操作系统operatingsystem位于硬件computerhardware之上,应用程序applicationprograms又位于操作系统operatingsystem之上,各个应用程序如compiler(编译器),assembler(组译器),texteditor(文本编辑器),databasesystem(数据库