Quantcast
Channel: IT社区推荐资讯 - ITIndex.net
Viewing all 11848 articles
Browse latest View live

播客制作入门指南 2.0 - 少数派

$
0
0

在大约两年前,我为入坑播客制作的新人们写下了 《播客制作入门指南》一文,希望可以帮助新人主播快速跨过上手播客必要的技术门槛,更轻松地录制自己的节目。在过去的两年中,中文播客进入了快速增长期,大量新节目和新人主播如雨后春笋般出现在播客圈,这份指南在主播群体里广泛传阅,时常被一些播客群和播客活动提及。

不过,指南中的一些内容不够完善,还有部分内容随着环境的变化而显得不合时宜。因此,我决定调整和升级指南中的内容,保留基础框架的同时引入更适合当下播客创作的技巧和心得。这份指南依旧以「降低播客入门门槛」为初衷,希望它能让你的「第〇期」录起来更简单。

一、选题和准备

如果你希望自己的播客能够长期、稳定地获得听众,并形成良性传播,选择一个相对明确的播客主题非常重要。直白的主题能让听众对你的节目内容有一个大致的预期,也便于听众之间相互推荐时可以一句话说清楚你的节目在讲什么。相反,如果你的节目什么都聊,其他人也很难迅速判断你的节目是否值得订阅。

如果你不太确定节目想聊什么,可以想想到底是什么东西激发了你的表达欲,然后从这个灵感开始。我建议你选择自己了解或有兴趣长期钻研的话题。当你谈论自己熟悉的领域时,肯定更容易形成有价值的观点,对某个领域的长期兴趣也能支持你把节目持续做下去,避免「更了三期就开始放鸽子」的情况出现。

有了选题,你需要确定播客名称,并准备一句节目介绍,还需要确定节目 logo 并制作封面图。封面图的尺寸以大于 2000 x 2000 为佳,3000 x 3000 更好。

二、录音

设备的选择

在正式购买录音设备之前,我建议你先使用手机或电脑试录你的第〇期内容。你可以借助这个过程先行了解做播客的流程,顺带测试你的录音环境是否达标。较新款的旗舰和手机都配备了不错的麦克风,即使未来你购买了更专业的录音设备,手机或电脑自带麦克风的录音质量依然可以拿来应急。

在熟悉基本流程后,你就可以考虑购入自己的录音设备了。市面上的相关产品很多,产品推荐类的影片、文章也有不少。总体来说,做播客需要用到麦克风、录音机和监听耳机。

录音所需的三类设备

常见的消费级麦克风分为动圈和电容两类。抛开原理不谈,两类麦克风的主要区别在于收音特点不同——动圈麦克风相对不敏感,多以定向麦为主,非常适合多人录制时每位主播各拿一个收声,或者在有底噪的环境里录音;电容麦克风比较灵敏,能收录很多声音细节,适合单人录音或录制乐器等。

目前,多数多人节目都使用动圈麦克风录制,得益于动圈麦不敏感的特点,每个主播都可以把自己的声音单独录成一轨,便于后期剪辑。

有些带有 USB 接口的麦克风可以直连电脑,使用电脑上的录音软体就能录音。还有一些则使用 XLR 接口,它们不能直接插在电脑上,有两种方案可以完成转接:一是使用音频介面(Audio Interface),二是使用 XLR to USB 转接线。

XLR 接口

两者本质上都是转接器,只是功能复杂度略有不同。音频介面在国内电商平台常被称为「声卡」,除了能让你的电脑连上 XLR 设备,它们通常还可以调节音量、外接监听耳机等。XLR to USB 转接线则和你用过的其它转接线没什么大区别——一头是 XLR 接口,另一头是 USB 接口。

在我派长期服役的 Focusrite Scarlett 2i2 音频介面

录音也不一定要用电脑,市面上还有大量的专业录音机,它们可以直连 XLR 麦克风,还能插入存储卡以保存录音。Zoom 的经典产品 Zoom H6 就是其中代表,它也是被播客主播使用最多的录音机。录音机功能单一,稳定性高,不会出现电脑常见的「节目录到一半,录音应用闪退了」等情况,而且外出录音会比带着电脑方便很多,如果有预算的话完全应该购买。

经典的 Zoom H6,可以直插 XLR 设备,并进行多轨机内录音。图片来自 bhphotovideo.com

除了收音设备,我还建议你准备一个监听耳机。这个耳机既可以是你日常在用的普通耳机,也可以购买专用的监听耳机(如 SONY 经典型号 7506)。但请注意,一定要用有线耳机来做监听,无线耳机都有延迟,对监听效果影响很大。

监听耳机的作用有二,其一是帮你实时确认话筒运作是否正常,避免录音事故;其二是把你说的内容实时反馈到耳内,让你的思路更清晰。你一定要经历过一次录音,才能深切体会到「我靠我当时都他妈在说什么啊」是一种怎样的体验,这也是返听很重要的原因所在。

录音环境

无论后期处理能力如何强大,都不如前期录音环境的小小改善。请确保录音环境安静且尽可能没有回音。对于家里比较空旷而回音较大的主播而言,「用被子把自己裹起来,躲在被子里录音」是一个成本很低却效果很好的录音方式,许多职业主播甚至也在采用这种方法录音。当然,如果你有条件改造录音环境,也可以在家里贴上吸音棉,或为自己专门设置一块封闭、独立的录音区域。

被窝录音差不多就是图中这个意思,图片来自 YouTuber Pat Flynn 的节目封面

租借场地是另外一个提升录音环境的好办法。租借场地有两种方案,其一是专门租用为播客主播提供的录音间,在国内的部分地区已经有相关从业者(譬如老袁的播客公社、小宇宙等)为主播们提供场地支持,这些场地通常都准备好了录音设备,你只要去到现场张嘴说话即可;其二是租用自习室,自习室是近几年在国内流行起来的公共空间,部分自习室提供会议室(或洽谈室)甚至直播室,其室内经过消音改造,同样适合播客录制。《一派·Podcast》的这期节目就是在深圳的一个洽谈室内录制的。

当前市面上有很多通过机器学习和算法来改善录音质量的工具,这些工具在某些场景下确实可以做得不错,但终究不能从本质上改变声音档案的质量。它们可以作为你在录音或剪辑中的辅助工具,但录音环境的重要性无可替代。

录音的流程

播客录音通常分为线下录音和线上录音,两种录音方式各有一套截然不同的工作流,需要面对的问题也不尽相同。

最简单的是单人录音,只需要找个安静的地方直接对着麦克风说话就行。单口节目考验得更多的是主播本人的表达能力和观点输出,如果哪些段落聊得不够好还可以反复录制和剪辑,后期空间很大。

比较麻烦的是需要多人参与且采用线下录音的节目,推荐使用动圈麦克风进行录音。动圈麦克风的特点是收音集中且对环境音的敏感度较低,所以当多人一起聊天时,每个人的麦克风都不会收录其他人的声音。你需要将每个人说的话单独录成一轨,这样做的好处是后期剪辑时如果遇到抢话、说错话等情况,可以分轨处理,让剪辑更容易。

动圈麦对远距离声音不敏感,更适合用来多人同场线下录音

线上录音更为复杂,主要难点在于你要确保参与节目的其他人也处在安静的环境中,并且他们的录音设备没有问题。线上录音通常采用「multi-ender」的方式,即每个人都准备两部设备,一部用于语音通话(譬如使用 Zoom、Skype 或微信语音),另外一部则用来录制自己的声音。当在线谈话结束后,大家都将自己的录音统一汇总给负责剪辑的人,由他合并和后期处理。

博物志》主播于婉莹曾手绘过一幅录音过程示意图,你也可以参考其中要点——准备两部设备,一部用于通话,另一部用于录音;两部设备都要开启静音或飞行模式,避免打扰;如果用手机录音,记得垫高手机,让麦克风尽量靠近你的嘴。

远程录音示意图

录音中记得关闭手机或开启勿扰模式,尤其在线录音,很有可能突然被电话打断。如果录音真的被打断了也不要紧,所有人都不要停止录音,处理好问题后继续开录就行。

录音结束后,所有参与者要通过网盘等工具把各自的录音文件汇总至剪辑者手中,便于对方后期剪辑。

录音时的注意事项

对于新人主播而言,在录音的过程中逐渐学会「完整保留一句话」非常重要,即当某个地方说错的时候,立即将这句话的正确版本完整地重复一遍。没有经验的主播常常会在说错某个词之后直接从正确的地方说下去,这样会导致后期剪辑不便——如果出错的地方恰好是某个词中间,就有可能出现「说错的地方需要剪掉,说对的内容又不完整」的情况。因此,重复一整句话是更稳妥的办法。

婉莹还推荐过一个治口癖的好方法:在便利贴把自己常说的口癖贴在看得见的地方,用来提醒自己。每当自己录音时说到词汇,就把立刻把这句话去掉口癖重说一遍。

如果你的节目有嘉宾,记得在录音时提醒对方不要乱动。许多人在讲话时会不自觉地离麦克风越来越远,或者搓腿、跺脚、挠头等,这些动作都会影响录音质量且完全无法修复。如果嘉宾说话时出现以上状况,可以及时提醒对方,并让他把话重复一遍。

总而言之,你可以把播客视为综艺节目,节目的效果由前期素材和后期剪辑共同决定。不要害怕在录音时犯错或重复,因为听众最终听到的都会是剪辑后的版本。

三、剪辑

剪辑通常分为两个部分,分别是内容剪辑和音效调整。

内容剪辑指通过各种技术手段修改和调整音档内容的过程,最常见的就是去除录音中的「嗯」、「啊」、空白、口误等部分,让表达更加流畅。这个步骤相对比较机械,基本就是在重复「切断——删除——拼合」的过程。

分段、分轨剪辑

音效调整指对声音的质量和效果进行修改,最常见的是降噪、去回声、调整 EQ、压限等、音量均衡等。

通常来说,剪辑的第一步都是降噪。无论你的录音环境如何,降噪都可以让人声更清晰。最常用的免费降噪工具是 Audacity,它同时支援 Windows 和 Mac 平台。Audacity 同时还能完成去回声的工作,如果你录音的环境比较空旷,可以一试。

Adobe Audition 用户可以使用自带的降噪功能。其原理和 Audacity 一样,都需要先截取一段背景噪音,然后软体会自动生成一个反向声波,贯穿整条音轨,把噪声抵消掉。Bose、SONY 等厂牌旗下的主动降噪耳机采用的也是这个原理。

进阶方案是购买 iZotope 出品的 RX 8 系列插件,插件内包含了降噪、去回声、去破音等常用功能,并使用机器学习算法来处理声音。从效果上来说,iZotope RX 8 的降噪远超其它方案。此外,类似 RX 8 等第三方插件可以与 Garageband、Logic Pro X、Adobe Audion 等任何音频处理软件配合使用,不受平台及工具的限制。

在输出音频前,记得做一次音量均衡,这个过程可以让节目中每一轨的音量都保持同样大小,避免出现「主持人声音好大,但嘉宾声音听不见」的情况。 音量平衡通常使用 LUFS 作为音量单位,它衡量的是一段声音的平均响度(而你更熟悉的音量单位分贝(dB)衡量的则是瞬间响度)。因此,LUFS 更能代表一条音轨的整体音量大小。

不同的剪辑工具内调整 LUFS 的方式也各有不同,无法一概而论(其中一些还需要加载第三方插件才能实现)。如果你想了解更多信息,可以将自己在用的工具加上 LUFS 作为关键字,搜索相关教程(譬如「Logic Pro X + LUFS」)。在诸多剪辑工具中,Reaper 调整 LUFS 的方式最简单,挂载 SWS Extension 后就能在应用内直接修改,我就设置了「Command + Shift + L」一键将所选音轨调整至 -16 LUFS 的快捷键。

将声音指定为 -16 LUFS

所有调整完毕后,输出声音文件(Render)即可。一般来说,128 Kbps 的 mp3 格式文件就能满足谈话类节目的音质要求,但你也可以根据各托管平台对文件体积的限制来调整输出文件的解析度。只要平台不限,音质当然越高越好。

Render 时可选声音格式、音质等

四、放送

有了制作好的声音文件,接下来就要把它发布出去了。在这个环节,你要先选择一家托管服务商上传你的音档,然后再把它发布到 Apple、Google、Spotify 等平台。这个过程类似你把某个文件上传至百度网盘,然后给其他人网盘链接,对方点击链接就能获得你要分享的内容。

播客的放送流程

目前,国内播客常用的播客托管服务商为 Fireside、Typlog、Anchor 和喜马拉雅等。Fireside 在大陆地区访问速度不佳,Anchor 据说有无法访问的问题,需要留意。少数派旗下的播客节目都在两个月前从 Fireside 迁移到了 Typlog。

注意,上传(托管)和发布其实是两件事,但国内的播客平台(如喜马拉雅等)将这两件事合并成了一件,即当你把音档传至喜马拉雅的同时,节目也就在喜马拉雅平台发布了。但对于 Apple 等通用平台,你需要另外找一个地方托管音档,并把它提交给 Apple,听众们才能看到你的节目。

所有泛用性播客平台——如 Pocket Casts、Overcast、Castro 等——都是通过抓取 Apple Podcast 的节目数据库来完成搜索和订阅的。关于 Apple Podcast 与泛用性播客客户端的关系,建议收听 这期节目了解其原理。

大陆地区上架播客还需要面对 Apple Podcast 中国区审核的问题,我派作者 甜食已经撰写了一篇非常详尽的 中国区播客上架指导,这是目前为止关于该主题结论最明确(甚至唯一给出准确解答)的文章,建议阅读。

Apple Podcast 中国区的四家合作伙伴,将节目托管至这四个平台可以直接通过 Apple Podcast 审核

将你的播客节目发布至 Apple Podcast、Google Podcast 和 Spotify 的地址分别是 这里这里这里

五、运营

走到这一步,恭喜你的新节目开播啦。但一切到这里还没有结束,如果你希望节目能长久地做下去,就要为之后的用户运营做好准备。

微博、微信公众号、Twitter、Telegram 等是各播客栏目常用的社交平台,你可以在这些平台发布节目预告、更新通知等重要讯息,便于听众们及时了解节目动态。不过,对于前期听众较少的节目来说,着重经营一两个渠道是更高效的方案。运营社交媒体的核心目的是让你的听众有一个「落脚点」,让大家可以第一时间了解到你的节目动态。因此,你不需要在一开始就遍地开花,投入大量精力经营多个社交媒体。

或许你还需要准备一个听众群,吸纳更多的听众交流互动,至于选择微信、Telegram 还是 Slack,就完全取决于你的判断啦。和社交媒体一样,经营听众群也需要投入大量时间,在建群之前,你要考虑清楚自己的节目是不是真的需要让听众聚在一个群里闲聊,以及听众群对你的节目增长是否真的有意义。

别忘了准备一个邮箱,接收听众来信。

六、总结

以上就是从零开始做播客的要点咯。这篇文章中没有涉及更深入的技术问题,当你已经渡过了入门期之后,一定会渐渐摸到播客制作的门道和更多技巧。祝你开播顺利,新节目开播也别忘了告诉少数派的读者们,让我们一起进步。

拓展阅读

> 下载 少数派 2.0 客户端、关注 少数派公众号,解锁全新阅读体验 📰

> 实用、好用的 正版软件,少数派为你呈现 🚀


基于会话推荐系统最新长文综述,163篇参考文献,已被ACM Computing Surveys接收

$
0
0
一. 论文简介

本文给大家介绍一篇刚被 ACM 旗舰期刊 ACM Computing Surveys (CSUR) 接收的基于会话推荐系统 (Session-based Recommender Systems (SBRS)) 的综述长文。ACM Computing Surveys 是计算机学科最具影响力的期刊之一,其最新影响因子为 7.99,为中科院认定的一区 Top 期刊,CORE Rank A* 期刊,主要发表计算机科学领域较有代表性的综述论文。

文章题为《A Survey on Session-based Recommender Systems》,论文一作为麦考瑞大学博后Shoujin Wang,研究方向为数据挖掘,机器学习以及推荐系统。这篇文章是基于会话的推荐系统方向的一篇较为系统全面的综述文章。全文共 39 页,包含 11 个 sections、4 幅插图、11 张表格和 163 篇该领域内有代表性的参考文献。该文基于作者长期的积累和思考,对基于会话推荐系统这一推荐系统子领域进行了全面而深入的梳理和总结。

该文对目前文献中存在的各种各样的对问题的定义进行了统一的形式化,系统地定义了基于会话推荐系统的场景,任务和基本问题以及基本方法。作者从数据特征的角度出发,系统分析了 session 数据所特有的基本特征,以及他们给推荐任务带来的挑战。然后系统而全面地对这一领域当前的进展进行了归纳总结,包括对方法的分类和比较,对每类方法基本思想和特征的阐述。梳理和总结了基于会话推荐系统的主要应用场景,代表性算法和公开的数据集,并提供了开源链接。最后分享了本领域的未来可能的研究方向。

该文由浅入深,语言力求通俗易懂,举例丰富,既有深入的理论分析,又有应用,算法和数据集,既适合科研工作者阅读,也适合工程人员阅读。作者希望该文能给相关的研究人员提供一个对该领域研究的主要问题以及涉及的各个方面、主要挑战和进展一个全面而综合的了解,同时给未来的研究提供一些启发。

论文预印版链接:
https://www.researchgate.net/profile/Shoujin-Wang/research
https://arxiv.org/abs/1902.04864

二. 论文解读

0. 摘要

在当今的信息过载和数字经济时代,推荐系统在消费、服务和决策制定等方面正发挥着日益重要的作用。近些年来,基于会话的推荐系统(session-based recommender systems (SBRSs)) ,作为推荐系统的一种新的范式,正在兴起。不同于其他传统的推荐系统,如基于内容的推荐系统和协同过滤推荐系统,通常建模用户的长期和静态的偏好,基于会话的推荐系统旨在捕获用户短期和动态的偏好来给用户提供更实时和精准的推荐服务。这些推荐服务能对用户不断发展和变化的会话上下文场景具有较好的敏感性。尽管基于会话的推荐系统已经被广泛研究,目前既没有对基于会话的推荐系统的一个统一的问题定义和陈述,也没有对基于会话的推荐系统的特征和挑战的一个深入阐述。通常,人们并不太清楚基于会话的推荐系统的挑战被解决到什么程度了,以及这一领域的总体研究概况是什么样的。

这篇全面综述通过深入探索和讨论基于会话的推荐系统所涉及的主体 (比如会话),行为(比如用户对物品的点击),以及他们的特性(比如会话的长度) 来解决上述问题。研究者提出了一个通用的基于会话的推荐系统的问题陈述,概括和总结了这一领域多样化的数据特征和挑战,并且定义了一个分类方法来对该领域内代表性的研究进行分类。研究者讨论了基于会话的推荐系统在现实场景中的主要应用领域,整理了典型的算法和常用的数据集。最后研究者讨论了在这个充满活力的研究领域内的新的研究机会。

1. 引言

推荐系统已经发展成为人们进行快速有效选择和决策的一个基本工具。它已经渗透到我们日常生活的方方面面,包括生活、工作、学习、娱乐、社交和商业运营。推荐系统的作用在数字经济中和信息日益过载的时代显得尤为重要,因为用户通常需要从大量的和快速增长的内容、产品和服务(统称为物品 (item))中选择他们所需要的。因此,各种各样的推荐系统研究领域兴起并取得了成功,比如基于内容的推荐系统,协同过滤推荐系统和混合型推荐系统

然而,这些推荐系统倾向于利用所有的用户与物品之间的交互信息来学习每个用户对物品的长期和静态的偏好。这种做法通常是建立在一个隐含的假设之上的,那就是一个用户的所有的历史交互行为对他当前的偏好是同等重要的。这可能与现实不相符合,主要原因有两点:
  • 首先,一个用户对物品的选择不仅依赖于他长期以来形成的偏好,而且依赖于他短期的最近的偏好和跟时间相关的上下文场景(比如他最近浏览或者购买过的物品)。这种短期偏好通常隐含在用户的最近发生的与物品的交互行为之中,而这类最近的交互行为通常仅占用户所有交互行为的很小一部分。

  • 其次,一个用户对物品的偏好通常是动态变化而非静止的,它会随着时间的推移而演变。

近些年来,为了弥补上述不足,基于会话的推荐系统 (session-based recommender systems (SBRSs)) 悄然兴起,并引起了越来越多的关注。不同于上述推荐系统,基于会话的推荐系统从用户在交易过程中产生的会话 (session) 数据来挖掘和学习用户的偏好。每一个会话包含在一段连续的时间段内发生的多个「用户–物品交互行为」,比如某用户在一次交易会话 (比如从登录电商平台的账号到退出账号这段时间)中购买了一篮子物品。通过将每一个会话作为最基本的输入数据单元,一个基于会话的推荐系统能够从一个用户的最近产生的会话中捕获他的短期偏好,以及从一个会话到另一个会话之间的偏好的变化,从而进行更精准和实时的推荐。

在本文中,研究者用基于会话的推荐系统来指代那些所有以 session 数据为中心来推荐当前会话里的下一个物品,接下来的所有物品以及下一个会话里的所有物品的推荐系统。这个定义包括了有些文献中的一些狭义的基于会话的推荐系统,它们只推荐当前会话里的下一个物品。

对于基于会话的推荐系统,文献中存在各种各样不同的工作。这些工作通常用不同的词语来描述,建立在不同的场景设置和假设之上,针对不同的应用领域。比如,Hidasi et al. 在匿名会话数据上建立了一个基于会话的推荐系统。他们通过假设会话内部的交互行为之间存在严格的先后顺序来预测用户接下来想要点击的物品或者想看的电影。Hu et al. 则在非匿名会话数据上建立了另一个基于会话的推荐系统来推荐用户下一个可能想购买的物品,他们没有假设会话内部存在严格的顺序。Jing et al. 则基于非匿名会话数据设计了一个基于会话的推荐系统来推荐用户想要听的下一首歌或者想看的下一部电影,他们假设会话内部存在顺序。

虽然基于会话的推荐系统广泛存在于各个领域并且很多相关的研究都已经开展了,但是在这个领域还存在很多的由不同的描述,假设,场景设置和应用领域导致的不一致性。而且,没有一个统一的框架可以对现有的工作进行分类,对于基于会话的推荐系统也还没有统一的问题陈述。更重要的是,没有人对基于会话的推荐系统的特征(包括问题和数据方面的), 挑战和研究进展进行系统的讨论,也没有人对代表性的和最先进的方法进行系统的分类。这些缺陷限制了基于会话的推荐系统的理论发展和实际应用。为了弥补上面提到的不同方面的缺陷,本文对基于会话的推荐系统提供了一个综合而系统性的概览和综述。

本文的主要贡献如下:
  • 研究者提供了一个统一的框架来对基于会话的推荐系统的相关工作进行分类,从而有效的缓解了这一领域内的不一致性。

  • 研究者首次为基于会话的推荐系统提出了一个统一的问题陈述,在该陈述中,一个基于会话的推荐系统是建立在以下几个正式的概念之上的:用户、物品、动作、交互和会话。

  • 研究者对会话数据的基本特征以及它给基于会话的推荐系统带来的挑战提供了一个综合的概览。据了解,这是该领域内的第一次这样的描述。

  • 研究者对基于会话的推荐系统的各类方法进行了系统的分类和比较,从而可以看出该领域的各个挑战被解决到什么程度了,以及该领域当前的进展如何。

  • 研究者对每一类方法简单介绍了主要的技术细节,从而给读者对基于会话的推荐系统的当前进展提供一个深入的了解。

  • 研究者分析和讨论了基于会话的推荐系统的主要的实际应用领域和场景、收集和整理了典型算法的开源代码和常用的公开数据集。

  • 最后,研究者讨论和分享了基于会话的推荐系统的一些开放的研究问题和可能的研究方向。

2. 相关工作

文献中存在各种不同的既关于基于会话的推荐系统,也关于序列推荐系统的研究。序列推荐系统是与基于会话的推荐系统紧密相关但不同的领域。即使在基于会话的推荐系统中也存在很多不同的子领域,比如下一个物品推荐、下一个购物篮推荐等。因此,很多用不同词语描述的不同的工作混杂在一块,导致整个领域内没有一个统一和一致的描述,很容易让人混淆。在这一节,研究者首先澄清基于会话的推荐系统和序列推荐系统的概念以及他们之间的差异,然后提出一个整体框架来统一组织基于会话的推荐系统内的各种不同研究,最后阐述这篇综述跟已有的相关综述之间的差异。

2.1 基于会话的推荐系统 vs. 序列推荐系统

2.2 统一组织基于会话的推荐系统相关工作的框架

根据推荐任务的不同,基于会话的推荐系统可以划分为对当前会话内下一个交互行为(通常是下一个物品)的推荐,对当前会话内剩余所有交互行为的推荐和对下一个会话的推荐。

2.3 相关的综述(详见原文)

3. 基于会话的推荐系统问题陈述

一个推荐系统可以看作一个系统,它包含多个基本主体:用户、物品、他们间的交互行为。这些基本的主体和行为构成会话的基本组成部分,而会话是基于会话的推荐系统的核心主体。因此研究者首先介绍这些主体和行为的定义及属性,然后在他们基础之上定义基于会话的推荐系统的研究问题。这些定义和属性将进一步用来对基于会话的推荐系统进行刻画和分类。
  • 3.1 用户以及用户的属性

  • 3.2 物品以及物品的属性

  • 3.3 行为以及行为的属性

  • 3.4 会话以及会话的属性

  • 3.5 基于会话的推荐系统的研究问题陈述

4. 特征和挑战

基于会话的推荐系统建立在会话数据之上,不同类型的会话数据通常具有不同的特征,这些特征本质上给基于会话的推荐系统带来了不同的挑战。本节首先描述根据会话 (session) 的属性所划分的不同类型的会话数据,然后讨论每一类会话数据的特征和挑战。
  • 4.1 与会话长度相关的特征和挑战

  • 4.2 与会话内部顺序相关的特征和挑战

  • 4.3 与行为类型相关的特征和挑战

  • 4.4 与用户信息相关的特征和挑战

  • 4.5 与会话数据结构相关的特征和挑战

5. 基于会话推荐系统方法的分类和比较

5.1 基于会话推荐系统方法的分类

根据采用的技术,基于会话推荐系统方法可以分为 3 大类:传统方法,基于嵌入表征学习的方法,基于神经网络的方法。这 3 大类又可以进一步分为 8 类。

5.2 不同类方法之间的比较

6. 传统的基于会话推荐系统方法

传统方法采用传统的数据挖掘或者机器学习技术来挖掘会话数据内部的相关性,从而进行会话推荐。传统方法主要包含 4 类:
  • 6.1 基于模式 / 规则挖掘的方法

  • 6.2 基于最近邻模型的方法

  • 6.3 基于马尔科夫链的方法

  • 6.4 基于生成式概率模型的方法

  • 6.5 传统方法之间的比较

7. 基于嵌入表征学习 (latent representation) 的方法
  • 7.1 基于潜在因子 (latent factor) 模型的方法

  • 7.2 基于分布式表征 (distributed representation) 的方法

  • 7.3 基于嵌入表征学习的方法间的比较

8. 基于深度神经网络的方法

  • 8.1 基于基本的深度神经的方法

  • 8.1.1 基于 RNN 的方法

  • 8.1.2 基于 MLP 的方法

  • 8.1.3 基于 CNN 的方法

  • 8.1.4 基于 GNN 的方法

  • 8.2 基于高级模型的方法

  • 8.2.1 基于注意力模型的方法

  • 8.2.2 基于记忆网络的方法

  • 8.2.3 基于混合专家模型的方法

  • 8.2.4 基于生成模型的方法

  • 8.2.5 基于强化学习的方法

  • 8.3 基于深度神经网络的方法间的比较

9. 基于会话推荐系统的应用,算法和数据集

9.1 基于会话推荐系统的应用

基于会话推荐系统已经被广泛应用于现实世界的各个领域和场景当中,来使客户和企业获利。下表总结了这些传统的和新兴的应用领域。

  • 9.2 开源算法和公开数据集

  • 9.2.1 开源算法整理

9.2.2 公开数据集整理

10. 展望和未来的研究方向

  • 10.1 考虑一般用户偏好的基于会话推荐系统

  • 10.2 考虑更多场景及上下文影响因素的基于会话推荐系统

  • 10.3 考虑跨域信息的基于会话推荐系统

  • 10.4 考虑更多用户行为模式的基于会话推荐系统

  • 10.5 考虑约束条件的基于会话推荐系统

  • 10.6 交互式的基于会话推荐系统

  • 10.7 在线或者流式的基于会话推荐系统


11. 结论

在本文中,研究者对当前的基于会话的推荐系统的最具代表性的工作进行了系统而广泛的调研。研究者提出了一个统一的框架来把这个领域内各种各样的工作归结为 3 大类,同时提出了一个统一的问题陈述来消除该领域内存在的各种不一致性,以减少读者的疑惑。研究者透彻地分析了会话数据的独有特征以及他们给基于会话的推荐系统所带来的挑战。研究者提出了一个分类机制来对现有的基于会话的推荐系统的方法进行分类,阐述了每一类方法的核心思想和一些关键的技术细节。此外研究者讨论了基于会话的推荐系统的实际应用领域和场景,收集和整理了一些典型的算法和数据集。最后研究者讨论了该领域一些可能的研究方向。关于基于会话的推荐系统的研究正方兴未艾,大量的新技术和新方法正在不断涌现出来。研究者希望这篇综述能给读者在关于这个领域的主要问题,关键挑战,最新进展以及主要方法和应用等方面带来一个综合而全面的了解。

相关综述文章:

[1] Shoujin Wang, Liang Hu, Yan Wang, Xiangnan He, Quan Z. Sheng, Mehmet A. Orgun, Longbing Cao, Francesco Ricci, Philip S. Yu. Graph Learning based Recommender Systems: A Review. In Proceedings of the 30th International Joint Conference on Artificial Intelligence (IJCAI 2021 Survey Track), 1-9, 2021. Preprint version: https://www.researchgate.net/profile/Shoujin-Wang
[2] Shoujin Wang, Liang Hu, Yan Wang, Longbing Cao, Quan Z. Sheng, Mehmet A. Orgun. Sequential Recommender Systems: Challenges, Progress and Prospects. In Proceedings of the 28th International Joint Conference on Artificial Intelligence (IJCAI 2019 Survey Track), 6332-6338, 2019. Preprint version: https://www.researchgate.net/profile/Shoujin-Wang

部分参考文献:

Shoujin Wang, Longbing Cao, Yan Wang, Quan Z. Sheng, Mehmet A. Orgun, Defu Lian. A Survey on Session-based Recommender Systems. ACM Computing Surveys (CSUR 2021), 1-39, (accepted).
Shoujin Wang, Liang Hu, Yan Wang, Xiangnan He, Quan Z. Sheng, Mehmet A. Orgun, Longbing Cao, Francesco Ricci, Philip S. Yu. Graph Learning based Recommender Systems: A Review. In Proceedings of the 30th International Joint Conference on Artificial Intelligence (IJCAI 2021 Survey Track), 1-9, 2021.
Shoujin Wang, Liang Hu, Yan Wang, Longbing Cao, Quan Z. Sheng, Mehmet A. Orgun. Sequential Recommender Systems: Challenges, Progress and Prospects. In Proceedings of the 28th International Joint Conference on Artificial Intelligence (IJCAI 2019 Survey Track), 6332-6338, 2019.
Shoujin Wang, Liang Hu, Yan Wang, Quan Z. Sheng, Mehmet A. Orgun, Longbing Cao. Modeling Multi-Purpose Sessions for Next-Item Recommendations via Mixture-Channel Purpose Routing Networks. In Proceedings of the 28th International Joint Conference on Artificial Intelligence (IJCAI 2019), 6332-6338, 2019.
Shoujin Wang, Liang Hu, Longbing Cao, Xiaoshui Huang, Defu Lian, Wei Liu. Attention-based Transactional Context Embedding for Next-item Recommendation. In Proceedings of the 32nd AAAI Conference on Artificial Intelligence (AAAI 2018), 2532-2539, 2018.
Shoujin Wang, Liang Hu, Longbing Cao. Perceiving the Next Choice with Comprehensive Transaction Embeddings for Online Recommendation. In Proceedings of the 28th Joint European Conference on Machine Learning and Knowledge Discovery in Databases (ECML-PKDD 2017), 285-302, 2017.
Shoujin Wang, Liang Hu, Yan Wang, Quan Z. Sheng, Mehmet A. Orgun, Longbing Cao. Intention Nets: Psychology-inspired User Choice Behavior Modeling for Next-basket Prediction. In Proceedings of the 34th AAAI Conference on Artificial Intelligence (AAAI 2020),6259–6266, 2020.
Liang Hu, Longbing Cao, Shoujin Wang, et al. Diversifying Personalized Recommendation with User-session Context. In Proceedings of the 26th International Joint Conference on Artificial Intelligence (IJCAI 2017), 1858-1864, 2017.

免费开源剪辑软件Shotcut推荐和使用教程 - 简书

$
0
0

最近想剪辑一下教学视频,想着能不用盗版尽量不用盗版,况且自己的需求并不复杂,又不是剪辑电影电视剧了,就没有下载那几个大牌的剪辑软件。

简单研究了一下免费的剪辑软件,最后选择了Shutcut。这是一个开源的免费软件,官网地址是 https://shotcut.org/。官网进去是英文版的,不要恐慌,软件下载下来界面有中文版。

Shotcut软件的界面.png

下面大概说一下这个软件怎么使用。

导入素材,建立时间线

  1. 将需要剪辑的素材拖动到「播放列表」区域,将素材导入到软件。

  2. 点击时间线下面的「三横线符号」,打开附加操作菜单,在里面选择添加视频轨道,根据需要可以再添加音频轨道或多个视频轨道。

Shotcut剪辑-添加视频轨道.png
  1. 将素材拖动到对应的轨道上。如果需要素材先后播放,就拖动到同一个轨道上,如果需要视频以画中画的形式叠加播放,就拖动到不同轨道上。

音频视频对齐

教学视频往往会同时录制多个视频,比如一个是电脑录屏,一个是教师出境。

剪辑时如果两个视频没有对齐的话,教师的口型就对不上声音,或者PPT翻页和声音不一致。

Shotcut这个软件的一个好处是每个视频轨道都可以显示音频波形,通过对比音频波形可以很方便的对齐视频。视频对齐后,将其中一条的音轨关掉,保留收音效果较好的那一条视频的音轨。

音频对齐.png

调整画中画位置

改变上层视频的位置和大小

导入两个视频时,视频都会居中布置,如果需要调整上层视频的位置的话,需要在 「时间线」里面选中上层视频,然后在 「滤镜」中选择 「位置与尺寸」,就可以调整上层视频的位置了。

调整画中画位置.png

实际上,不光上层视频可以调整位置,下层视频也可以调整位置,从而做出两个视频并列的效果。

上层视频位置和大小的变换

有时在教学视频里面,上层视频(比较教师出境视频)的大小和位置是需要变化的,比如说PPT首页的时候,教师出境视频比较大,内页的时候,出境视频会比较小。

这种情况,首先需要对视频进行切割。选中需要切割的视频,将播放点的竖线拖动到你要切割的位置。在时间线上面的工具栏选择 「于播放点处切割」,选中的视频就可以被切割为2个视频,可以单独设置滤镜,选择 「位置和尺寸」滤镜,就可以重新设置上层视频的位置和尺寸了。

这里有一个小技巧,通过音频波形,可以迅速的找到PPT的翻页点,因为翻页点上基本不说话。

切割视频.png

因为上层视频发生了变化,为了不显得太突兀,可以增加一个淡入淡出的效果。

在前一段视频上增加一个 视频淡出滤镜,在后一段视频上增加一个 视频淡入滤镜。完成后时间轴上会出现两个半透明的三角形。

淡入淡出.png

显示字幕、文字

首先在视频轨道上方再增加一个新轨道。

然后在工具栏的 「打开其他」里面选择 「文本」,在打开的对话框里输入你要显示的文本内容。

插入文本.png

输入文本后点OK,在预览框里会显示文本的内容,将其拖动到新增加的轨道上。注意拖动的时候不要点中间那个点,要按住文本框的其他位置拖动。否则的话不会把文本框拖动到时间线上,而是会把文本框在画面上移动位置。

插入文本效果.png

将文本拖动到轨道上之后,就可以在滤镜里设置文本的字体、颜色等。

拖动文本效果.png

设置转场动画

如果在要把两个视频相连的话,可能需要设置转场动画。

将一个轨道上的两个视频重叠,重叠的部分就会变成紫色的沙漏形状。右键点击这个沙漏,选择 「属性」,就可以设置转场动画了。

转场动画.png

视频输出

最后就是进行视频输出了,也就是将剪辑好的视频按照一定的格式保存到本地。

Shutcut没有按照素材来源自动选择参数的功能(还是说我没发现?),需要手动选择参数。

在工具栏上选择 「输出」功能(图标是一个光盘💿),打开输出界面。来源选择 时间线,硬件编码器推荐不要勾选。勾选了硬件编码器的话,如果你的显卡支持硬件编码,导出会比较快,但是视频质量低于不使用硬件编码。

输出.png

左边的列表是常见的视频编码和参数选择,如果对编码器比较懂的话,还可以点 高级自己设置。如果对视频编码不太懂的话,这里推荐几个选项。

  1. 内建里面的「H.264 High Profile」,这个导出以后是「.mp4」格式,兼容性较好。

  2. 内建里面的「HEVC Main Profile」,这个导出以后也是「.MP4」文件。HEVC也叫H.265,压缩率比H.264高一些,但是个别老一点的设备可能不兼容。

选择格式之后,点击 「输出文件」,选择保存位置。

确定后,在界面最右边的任务里面会显示进度,泡杯茶耐心等待吧。

漫长的进度条.png

本文同时发表在我的博客 「吕旭说」上。

夏天冻死人的失温,被忽视的运动杀手

$
0
0
夏天冻死人的失温,被忽视的运动杀手

虎嗅注:白银山地马拉松赛事已有21人遇难,这起悲剧背后,是一个越野跑者以外的人很少听到的专业名词“失温“。失温到底是怎么回事?我们又该如何避免这样的惨剧再次发生?本文来自微信公众号: 丁香医生(ID:DingXiangYiSheng),作者:丁香医生,原文标题:《突发 21 人遇难!夏天冻死人的失温,被忽视的运动杀手》题图来自视觉中国。

图片来源:央视新闻

今天,一个突发的噩耗引起了全网关注:甘肃越野马拉松事故导致 21 人死亡。而这起悲剧的关键,是个很多人都没有听说过的词:失温。

到底什么是失温?怎么发生的?

为什么跑步这么热的运动,还会失温?

失温后为什么参赛者无法自救?

随着越来越多的人对户外运动感兴趣,意外情况也频频发生,失温又被称为户外运动的头号杀手。

也许你觉得失温离自己很遥远,但实际上,失温死亡还有一个主要原因,是生活中很常见的事:醉酒。

今天就来和大家好好说一说,可怕的“失温”到底是怎么回事。

失温,不需要很冷就能发生

人体的核心温度是固定的。表面温度有时候可以波动,但一定会尽量维持核心温度 37~37.5℃ 的稳定。热了之后散热,冷了之后产热保持热度。

相对于出汗这种散热的方式,产热和保持热度比较被动,调节有限。所以就非常需要外界的被动衣物和住所来帮助自己抵御低温。这也是人类进化过程中从热带逐渐向寒带扩展的原因,只有掌握了一定的保温能力,才能在寒冷地区生活。

当我们缺乏衣物和住所保护,意外出现在冷环境中时,维持不了核心温度,失温就有可能发生,甚至不需要是在很寒冷的环境下。

例如这次事件,突发的恶劣天气加上跑步出汗,身体接触到冷风冷水,造成热量对流和传导散热,大量热量从皮肤和肺部损失,核心温度难以保持在标准范围。

通常来说,外界温度越低,风力越大,环境湿度越高,越容易失温。

事件发生的山地环境,图片来源:新华社

失温很有迷惑性,容易被忽视

失温并不是一开始就非常严重的,人体会顽强的通过代偿机制与这种低体温对抗。所以当暴露于低温环境后,会由轻到重逐渐失温。

当失温达到一定程度时,人会变得行动迟缓,如果忽略掉身体报警信号,误认为只是“有点疲惫”,觉得再坚持一下就没事了,就有可能最终造成悲剧。

及时发现和识别失温,快速采取措施非常重要。

失温首先出现的是代偿期,或者叫冷应激期。这个时候的核心温度在 35℃ 以上。

人体的精神状态完全正常,只是会感到有点儿冷。应对冷的方式是容易散失热量的周围血管收缩,减少热量从皮肤的散失,然后在甲状腺素、肾上腺素的影响下增加脂肪、肌肉、肝脏产热,以及开始寒战抖动产热。这样做的结果就是手脚因为血管收缩会冷得更厉害点儿,但能维持身体内部的需要,从这一期恢复,人体没有太大损伤。

其次是轻度失温:核心温度进一步降低到 35℃ 以下,32℃ 以上。

开始算作医学上定义的低体温症。代偿的产热还在进行,但已不足以维持正常机体功能了,呼吸心跳难以保证充足的供氧,所以代偿性的开始增加心跳呼吸,会心跳加速、呼吸频快。人体开始有一些怪怪的情况出现,比如判断力下降,说话不清楚、动作不协调。以及此时反常的尿多。此时已经很难靠自己脱困了,急需外界帮助。

再然后是中度失温,核心温度到了 28℃~32℃。

你可能听说过的冷到反常脱衣服就是这一时期出现。此时意识慢慢丧失,各种反射变得迟钝。肌肉寒战产热也不再进行了。从心跳快变成了心律不齐。反常脱衣服是一种身体调节机制的“投降”,实在是撑不下去了,原来始终收缩的周围血管扩张,导致短暂“热起来”的错觉。

最后就是难以拯救的重度失温了,核心温度来到 28℃ 以下。

没有意识,没有寒战,低血压,心跳减慢直到慢慢停止。

争分夺秒,科学施救失温

遭遇失温时最关键的,是首先去除导致失温的原因,其次根据失温的不同阶段做不同处理。

因为失温跟温度、湿度、风力都有关。所以应该尽快进入避风避雨场所,换上干燥衣物。有条件时保温转运至专业医疗救治场所。

图片来源:站酷海洛

复温的处理要遵循分级温和循序渐进的原则,不专业的施救反而可能加重对身体的危害。

1. 冷应激期:只需要被动的保持温度。裹上毯子和干燥的厚重衣物,热饮热的食物也有帮助。

2. 轻度失温:要注意避免周围的肌肉按摩,本来外周低温的血液回到内脏会带来更多伤害。在被动温度加热之后,再进行主动的加热毯和室温加热,室温推荐在 28℃。

3. 中度及重度失温:需要依赖主动核心加热复苏,比如在医疗场所进行的温热等渗液体腹腔冲洗。在缺少这些条件时,应尝试可能的复温方法,同时尽快实施转运。现场救援主要是做好包裹轻柔担架转运。

注意!不要试图给中重度的失温者进行四肢加热或者喝热水,大量低温血液回到循环带来的低血压和温度进一步降低会增加复苏失败的风险。

另外,对于失温的抢救,需要再努力一把。

中重度失温对身体组织尤其是大脑神经有一定的保护作用,可能会出现类似“假死”的状态:瞳孔放大、没有痛觉、心率和呼吸减慢,但实际上人还活着。

急救医学中,有原则叫:“低体温症患者应当被抢救。只有在接近正常体温时,才可宣告死亡。”

在保证自身安全的情况下,对失温人群的抢救可以更努力一些,只要还有一线希望都不应该放弃。

酒后和户外运动,尤其要注意预防失温

失温是严重的急性伤害事件,关键是预防。

预防失温其实很简单,不要长时间待在寒冷环境中,确保穿着足够温暖,风雨打湿衣物后尽快换下湿衣服。

但只是“多穿衣服”并不是绝对的保证。失温的发生和环境情况、身体状态、热量补充、运动节奏等很多因素有关。

有时候在特定情况下,遭遇失温的风险会增加。

比如饮酒者,醉酒后失温死亡是目前失温死亡的最重要原因。因为醉酒会错判外界的环境而导致进一步失温致死,另外饮酒更容易带来周围血管扩张,让热量更不容易保存在身体内。

再强调一遍:饮酒要有节制,不要相信饮酒可以御寒!喝酒不能取暖!

户外运动遭遇突发事件导致失温死亡意外,最近也有上升趋势。进行户外徒步越野跑等活动时,常常容易忽略身体给出的报警信号,只是考虑“再坚持一下”,这样也是很危险的。

参加户外越野运动的人群应该对失温保有警惕,在追求超越极限的同时保证安全。

  • 熟悉天气情况,根据天气情况做合适的衣物准备。保暖衣物、透气防风雨的冲锋衣都是需要的。

  • 参加比赛,各种强制安全装备不要忽视,这并不是额外的负重。

  • 熟悉环境,了解补给点的设置和呼叫救援方式。

  • 头部颈部等更容易散失热量的保暖尤其要注意。

  • 进食携带足够的高热量食物。

  • 遭遇降温风雨变化时量力而行,评估身体状态,不要硬撑,及时撤离。

Android WebView与Native通信总结

$
0
0

当前移动端App的开发很多都需要内嵌WebView来方便业务的快速开展,特别是电商App中,业务变化快,活动多。仅仅依靠native的开发方式难以满足快速的业务发展,于是混合开发模式便出现。当前比较知名的有 Cordova, Ionic, 国内的有 Appcan, APICloud开发平台,这几种都是依赖于WebView的实现。而Facebook的 React Native和阿里的 Weex是混合开发的另一种实现, React NativeWeex可以让原生开发者像H5开发一样写前端的代码,然后通过自己的SDK渲染成原生的组件,不依赖于 WebView。本文主要总结一下当前 WebView和native的交互方式。

Android中 WebViewJavaScript的交互,其实就是Android native与网页中的 Javascript之间的交互, 所以搞清楚了它们之间数据是如何传递的就明白了。以下从两个方面进行介绍:

Native 向 Javascript 发送数据

Native 向 JavaScript发送数据有两种方式, 一种是 evaluateJavascript另一种是 loadUrl。区别在于 evaluateJavascriptloadUrl更高效, evaluateJavascript在android 4.4之后才能用,该方法的执行不会使页面刷新, 而 loadUrl则会。所以通常我们如下使用:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    evaluateJavascript(jsCommand, null);
} else {
    loadUrl(jsCommand);
}
复制代码

当然,如果想要直接获得javascript代码的执行结果,我们可以这样写:

String command = "ABC";
webView.evaluateJavascript("(function() { return " + command + "; })();", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String result) {
        // 此处的result便是 ABC
    }
});
复制代码

Javascript 向 Native 发送数据

Javascript向Native发送数据有4种方式,第一种方式是借助 webChromClient中的 onJsAlert(), onJsPromot()的方法来获取Javascript相关数据。第二种方式是采用覆盖 shouldOverrideUrlLoading方法,拦截url协议。第三种是最方便的,也就是 @JavascriptInterface方案, 现在大多数App都会用到这种方式, 后面会详细介绍。最后一种是利用在 webView中嵌入 iframe的方式,通过更新 iframe的url。比较出名的混合框架 JsBridge之前就是采用这种方式,现已改成采用 @JavascriptInterface这种方式了。以下简单介绍一下各种方式的使用。

onJsPrompt

webChromeClient中提供了 onJsAlert, onJsPrompt方法,方便开发者重写Javascript中的 alert, prompt方法对应的行为。我们可以在这两个方法中任选一个做为native和js进行交互的桥梁。通常我们借助于 onJsPrompt方法来实现, 就是因为在js中,这个方法通常我们用得比较少。而对于 onJsAlert(), 当调用js中的 alert()时会触发,我们可以通过重写这个方法来实现自定义的提示View

但是这种方式对传入的数据量有限制,和手机的WebView版本有关,以我的测试机为例,在 oppo reno手机 android 10上面, 其传递数据最多只能是10k。 而用 @JavascriptInterface方案, 传递的数据最多可达20 - 30M

我们来看前端网页的写法, 直接调用 prompt函数

var data = prompt("native://getUserInfo?id=1");
console.log('data:' + data);
复制代码

在为WebView设置 WebChromeClient的时候重写 onJsPrompt方法,如下:


 @Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
    Uri uri = Uri.parse(message);
    //如果是调nativeAPI.
    if (url.startsWith("native://")) {
        result.confirm("call natvie api success");
        return true;
    }
    return super.onJsPrompt(view, url, message, defaultValue, result);
}
复制代码

shouldOverrideUrlLoading

前端页面的Js代码:

document.location="native://getUserInfo?id=1";
复制代码

native层面在为WebView设置 WebViewClient对象时,我们需要重写 shouldOverrideUrlLoading方法。需要注意的是, WebViewClient中有两个 shouldOverrideUrlLoading方法的定义:

  • public boolean shouldOverrideUrlLoading(WebView view, String url)
  • public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request)

其中上面一个在sdk中已被标记 Deprecated, 下面一个是在android 7.0中才引入的,所以为了避免兼容性问题。在使用时,建议这两个方法都重写。

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    //如果是调nativeAPI.
    if (url.startsWith("native://")) {
        Log.i("CommonWebViewClient", "shouldOverrideUrlLoading execute------>")
        return true;
    }
    return super.shouldOverrideUrlLoading(view, url);
}
复制代码

@JavascriptInterface

在 Android 4.2以下有安全漏洞, 但目前我们的app大部份最小支持版本都已经升到5.0了,这个可以忽略,当然感兴趣可以自己搜索。

在native层面,我们需为要WebView注入一个对象,用来处理两边的数据交互。注入方式如下:

  • 首先定义一个类来处理两边的交互:
public class HybridAPI {
    public static final String TAG = "HybridAPI";

    @JavascriptInterface
    public void sendToNative(final String message) {
        Log.i(TAG, "get data from js------------>" + message);

    }
}
复制代码
  • WebView中注入这个类的实例
HybridAPI hybridAPI = new HybridAPI();
webview.addJavascriptInterface(hybridAPI, "HybridAPI")
复制代码

在网页中直接用如下代码便可以将数据发送到native端

 HybridAPI.sendToNative('Hello');
复制代码

iframe

我们还可以利用 iframe进行请求伪造向native端发送数据的。思路是向网页中添加一个 iframe控件,通过修改其 src属性,触发native端的 shouldOverrideUrlLoading方法的执行, 同样,native端通过重写该方法,去拿到js端传过来的数据。具体操作方式如下:

var iframe = document.createElement('iframe');
iframe.style.display = 'none';
document.documentElement.appendChild(iframe);
iframe.src="native://getUserInfo?id=1";
复制代码

在操作完成后,我们再从当前的dom结构中移除这个组件。

setTimeout(function() {
    iframe && iframe.parentNode && iframe.parentNode.removeChild(iframe);
}, 100);
复制代码

具体实践

在前面总结了WebView和Native交互的几种方案。但距离实际项目使用还有一段距离,在实际项目开发中还有很多问题需要考虑。如:

  • 交互的规则如何定义
  • 数据如何传递
  • 调用之后,如何拿到回调的结果
  • 对于Javascript的请求,native端应该如何设计?
  • ....

native端向JavaScript发送消息只有 loadUrl, evaluateJavascript这两种方式。Javascript向native端发送信息可以利用 onJsPrompt, @JavascriptInterface, shouldOverrideUrlLoading等几种方案,以下 我们通过采用 @JavascriptInterface这种方式(也就是大家通常说的注解方案)为例来看看如何解决实际项目开发中碰到的问题。

交互的规则

首先我们来定义两端的交互规则。

Javascript向native发数据:

我们约定在H5中采用 HybridAPI.sendToNative方法向native端发送数据,于是我们需要在native端做如下支持:

  • 定义一个 HybridAPI类,并向WebView中注册
HybridAPI hybridAPI = new HybridAPI(this);
webview.addJavascriptInterface(hybridAPI, "HybridAPI");
复制代码
  • HybridAPI类中定义一个方法 sendToNative, 该方法暴露给Javascript用来给native发送数据
@JavascriptInterface
public void sendToNative(final String message) {
    Log.i(TAG, "get data from js------------>" + message);

}
复制代码

native层向Javascript发数据:

public final String TO_JAVASCRIPT_PREFIX = "javascript:HybridAPI.onReceiveData('%s')";

public void sendToJavaScript(Map message) {
    String str = new Gson().toJson(message);
    final String jsCommand = String.format(TO_JAVASCRIPT_PREFIX, escapeString(str));

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        evaluateJavascript(jsCommand, null);
    } else {
        loadUrl(jsCommand);
    }
}
复制代码

在H5中,我们这样写, 当native向Javascript发送数据时,便会触发Javascript中的 Hybrid.onReceiveData方法, 该方法就能接收到native层传过来的数据

HybridAPI.onReceiveData = function(message) {
    console.log('[response from native]' + message);
}
复制代码

数据结构的定义

在上面我们已经基于 @JavascriptInterface方案完成了native与WebView间通信机制的实现,双方可以交换数据,但开发的时候需要考虑更多问题。比如,如果是Javascript向native发送数据,需要将数据转换成一个字符串,然后再将字符串发给native, native再去解析这个字符串,找到对应的处理方法,提取出相关的业务参数,再进行相应的处理。所以我们需要定义这个字符串的数据结构。

在上面我们已经约定了,H5端可以采用 HybridAPI.sendToNative向native发送数据,该方法只有一个字符串参数, 以 获取用户信息这个业务功能为例,我们的字符串参数是 native://getUserInfo?id=1,这个字符串中的 getUserInfo表示当前通信的目的或行为(为了拿用户信息), ?后面的 id=1表示的是参数(用户id为1), 如果参数多了,这个字符串会更长,再如果上面涉及到中文的转码,其可读性会大大降低,所以这种交互方式不够直观和友好,我们期望用户采用下面这个方法去与native通信:

HybridAPI.invoke(methodName, params, callbackFun)

  • methodName: 当前通信的行为
  • params: 传递的参数
  • callbackFun: 接收native端的返回数据

于是,我们在js层面进行一层的封装

var callbackId = 0;
var callbackFunList = {}
HybridAPI.invoke = function(method, params, callbackFun) {
    var message = {
        method,
        params
    }
    if (callbackFun) {
        callbackId  = callbackId + 1;
        message.id = 'Hybrid_CB_' + callbackId;
        callbackFunList[callbackId] = callbackFun
    }
    HybridAPI.sendToNative(JSON.stringify(message));
}
复制代码

最终还是调用的是 sendToNative与native层进行通信,但是采用 HybridAPI.invoke方法对开发者更加友好。

由于需要在执行成功后调用回调函数。为此在发送消息的时候先把 callbackFun保存起来,在执行成功后再响应。 当Javascript请求发送到native层时,会触发 sendToNative方法,在该方法中, 我们来解析前端的数据:

@JavascriptInterface
public void sendToNative(final String message) {
    JSONObject object = DataUtil.str2JSONObject(message);
    if (object == null) {
        return;
    }
    final String callbackId = DataUtil.getStrInJSONObject(object, "id");
    final String method = DataUtil.getStrInJSONObject(object, "method");
    final String params = DataUtil.getStrInJSONObject(object, "params");

    handleAPI(method, params, callbackId);
}

private void handleAPI(String method, String params, String callbackId)  {
    if ("getDeviceInfo".equals(method)) {
        getDeviceInfo();
    } else if ("getUserInfo".equals(method)) {
        getUserInfo();
    } else if ('login'.equals(method)) {
        login();
    }
    ....
}
复制代码

native端在处理完成后,再调用 evaluateJavascriptloadUrl方法,反馈给前端。操作流程示例:

//指定了js端的接收入口 
public final String TO_JAVASCRIPT_PREFIX = "javascript:HybridAPI.onReceiveData('%s')";


public void callJs() {
    Map responseData = new HashMap<>();
    responseData.put("error", error);
    responseData.put("data", result);
    //回调函数的id标识,返回给js,这样才能找到对应的回调函数
    responseData.put("id", callbackId);
    sendToJavaScript(responseData);
}

public void sendToJavaScript(Map message) {
    String str = new Gson().toJson(message);
    final String jsCommand = String.format(TO_JAVASCRIPT_PREFIX, escapeString(str));

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        evaluateJavascript(jsCommand, null);
    } else {
        loadUrl(jsCommand);
    }
}

// 转义
private String escapeString(String javascript) {
    String result;
    result = javascript.replace("\\", "\\\\");
    result = result.replace("\"", "\\\"");
    result = result.replace("\'", "\\\'");
    result = result.replace("\n", "\\n");
    result = result.replace("\r", "\\r");
    result = result.replace("\f", "\\f");
    return result;
}
复制代码

在上面的 callJs方法中组织好相关的数据,然后利用 Gson进行序列化,再转进行字符串的转义,最终调用 evaluateJavascript或者 loadUrl来传递给js。于是js端便可以利用 HybridAPI.onReceiveData来接收到。

还记得这段代码中定义的 callbackFunList吗?在上面native给js返回数据的时候,会带上一个 id, 我们可以根据这个id找到本次通信的回调函数,然后将数据回调过去。

var callbackId = 0;
var callbackFunList = {} //看这里
HybridAPI.invoke = function(method, params, callbackFun) {
   var message = {
       method,
      params
   }
   if (callbackFun) {
       callbackId  = callbackId + 1;
       message.id = 'Hybrid_CB_' + callbackId;
       callbackFunList[callbackId] = callbackFun
   }
   HybridAPI.sendToNative(JSON.stringify(message));
}
复制代码

所以,我们js端接收数据,可能是这样子:

HybridAPI.onReceiveData = function(message) {
    var callbackFun = this.callbackFunList[message.id];
    if (callbackFun) {
      callbackFun(message.error || null, message.data);
    }
    delete this.callbackFunList[message.id];
}
复制代码

再回到我们上面的 获取用户信息这个业务功能,我们的写法就会是这样子了:

HybridAPI.invoke('getUserInfo', {"id": "1"}, function(error, data) {
    if (error) {
        console.log('获取用户信息失败');
    } else {
        console.log('username:' + data.username + ', age:' + data.age);
    }
});
复制代码

至此,我们就将一具完整的数据通信流程实现了,由js端用 HybridAPI.invoke(method, params, callbackFun)来向native端来发送数据,native处理完毕后,js端通过 callbackFun来接收数据。

改进

在上面的java代码中,我们可以看到,native层的入口是 sendToNative方法,该方法中解析传入的字符串,再交给 handleAPI方法来处理

@JavascriptInterface
public void sendToNative(final String message) {
    JSONObject object = DataUtil.str2JSONObject(message);
    if (object == null) {
        return;
    }
    final String callbackId = DataUtil.getStrInJSONObject(object, "id");
    final String method = DataUtil.getStrInJSONObject(object, "method");
    final String params = DataUtil.getStrInJSONObject(object, "params");

    handleAPI(method, params, callbackId);
}

private void handleAPI(String method, String params, String callbackId)  {
    if ("getDeviceInfo".equals(method)) {
        getDeviceInfo();
    } else if ("getUserInfo".equals(method)) {
        getUserInfo();
    } else if ('login'.equals(method)) {
        login();
    }
    ....
}
复制代码

我们会发现,随着业务的发展,项目的迭代,js端可能会需要native提供越来越多的能力,所以我们的 handleAPI方法中就会有越来越多的 if...else if...了。

于是,我们可以按业务来划分,新建一个 UserController类来处理 getUserInfo, login, logout这种与用户相关的native 接口。新建一个 DeviceController来处理类似于 getDeviceInfo, getDeviceXXX,... 等与设备信息相关的接口。然后我们再维护一个controller list, 每次调用js api的时候从这个list里面去找对应的 controller中的方法处理。

这样,就可以把具体的业务处理方法抽取出来。然而即便这样,还是避免不了在每个Controller中去写一段这个 if...else if ...这种代码。于是,其实我们可以很自然的想到用反射来做点事。

我们和H5开发约定好了,如果需要获取用户的信息,就调用 getUserInfo方法,这个方法名始终不变。同时,我们在Java端这样定义 UserController:

public class UserController implements IController{

    private volatile static UserController instance;
    private UserController() {}

    public static UserController getInstance() {
        if (instance == null) {
            synchronized(UserController.class) {
                if (instance == null) {
                    instance = new UserController();
                }
            }
        }
        return instance;
    }

    @APIMethod
    public UserInfo getUserInfo(Map params, String callbackId) {
        //TODO
    }

    @APIMethod
    public void login(Map params, INativeCallback callback) {
        //TODO
    }

    @APIMethod
    public boolean logout(Map params, INativeCallback callback) {
        //TODO
    }
}
复制代码

我们将该 UserController添加到上面提到的controller list中,然后我们在handleAPI方法中:

private void handleNativeAPI(String methodName,  String params, String callback) {
    for (IController controller : controllerList) {
        Method[] methods = controller.getClass().getDeclaredMethods();
        for (Method method : methods) {
            Annotation[] annotations = method.getAnnotations();
            for (Annotation annotation : annotations) {
                // 获取注解的具体类型
                Class annotationType = annotation.annotationType();
                if (method.getName().equals(methodName) &&  APIMethod.class == annotationType) {
                    try {
                        Map map = DataUtil.jsonStr2Map(params);
                        method.invoke(controller, map, callback);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                    return;
                }
            }
        }

    }
}
复制代码

后面,每当新增一个交互的方法时,我们只需要在对应的java类中写一个方法,并用 @APIMethod标识就可以。

以上我们总结了WebView与native通信的几种方式,并结合具体实践给出相应的实现思路,当然因为篇幅原因,这里并没有面面俱到。比如:

  • 如何实现H5端监听native端的某个事件的功能?
  • H5端监听native事件后,进行相应的操作,如何将操作的结果再返给native?
  • 如果js端调了一个不存的native的方法,应该如何处理?
  • ...

如果仔细理解了前面介绍的两端通信方式,实现上面的这些功能应该不是问题。但如果想把代码更好的封装,使开发者用起来更舒服,那就需要下一点功夫了。

晕轮效应

$
0
0

  本文9100字,向内看,多听批判的话。


这是智远的第0150篇成长笔记的分享。


我们先从一则场景开始:
多数人应该都看过 “还珠格格”“铁齿铜牙纪晓岚”两部电视剧。如果现在我问你对容嬷嬷的第一印象是什么?或许你会想到 她呲着牙,拿着针去扎紫薇和小燕子的场景。
如果我问你对纪晓岚的第一印象是什么?你可能会幻想出他那副 风流倜傥,不拘小节,善于言辞反应机敏诙谐挑战和珅的状态。如果你此时连带想起和珅,他那种油腻,狡猾的姿态便会出现在大脑中。
我们再换个场景,经朋友介绍你认识位小姐姐,周末你们约定好去咖啡厅认识下。
按照约定时间到达地方你找到合适位置坐下,在她未开口前,其实在心智中你已经有了对她第一印象的标准答案,比如, “她长的还行,真可爱”,接下来的聊天你都会围绕 这两个标签进行靠拢,不断强化,推演,迭代,合并。
回到家,若有朋友问你今天见的怎么样,你也会围绕今天所塑造的 “心智标签”进行回复。
上述种种场景带来的 “标签化”聚合,叫做 “晕轮效应”。  什么是晕轮效应?
概念提出者来自于美国著名心理学家爱德华·桑戴克(生平1874,8,31日—1949,8,9日)。简而概之,我们对人或事物留下的最初印象将会影响你对此事其他方面的判断。
“晕轮”,好比是当月亮被光环笼罩时产生的模糊不清的现象,多数人对事物和人的认知判断往往从局部出发,然后扩散到整体,这些带有 有色眼镜的局部认知往往会误导我们在大事面前做出正确判断。


01

以偏概全的心智模式


我们每个人的内心深处总是认为 人的品质之间是有着内在联系,比如心理学家戴恩曾经做过一组有趣的实验:
他准备一组照片,每个照片中的人与穿着打扮各有不同,然后让一批被测试者根据照片从特定的方面来评定这些人,经过数据统计被测试者赋能那些更有魅力的人一些理想的标签,比如:“和蔼,可亲,沉着,冷静,好相处”等等。
而事实上,晕轮的核心不仅表现在 以貌取人上,我们通常还会用眼光审视别人穿着的服装来判断其个人在社会中的“地位,性格”以及通过初次沟通语言谈断定他们的才能和人品等。
对不太熟悉的人进行评价时,“晕轮效应”显的格外明显,而晕轮背后信息摄入大脑后,是 “主我心理和客我心理”两者的博弈。
什么是主客我心理?
社会心理学家,象征性互动理论创始人米德认为, 人的“自我”意识就是伴随意义的传播活动而形成的。
自我是“主我”与“客我”的统一,可以分解成 相互联系,相互作用两个方面。一方面作为意愿和行动主体的“主我”,通过个人围绕对象事物从事的行为和反应体验出来。
另一方面作为他人的社会评价和期待之代表的“客我”,它是自我意识的社会关系性的体现。
简而概之,主我是个人的主体意识,后者是从周围观察到他人对自我的态度,评价和角色期待。
理论总是很难理解, 那我们讲个故事:
你清晨睡过了5分钟,为赶上9点钟的公交就在门口买提热的韭菜包子,于是在地铁上吃了起来,你发现有人瞪你 (客我表现),然后你觉得这样不好 (主我表现),产生自我的行为,于是就不吃了。
在这过程中,客我意识只有通过他人的意义或各种反馈交换(即传播)才会得到,“客我”与“主我”呈现为“互动关系”。
当接收信息后,内心会出现不断批判,衡量,最后形成“自我观”,这当中涉及到最重要因素为“自我心理互动效应”。
什么是内心的自我互动?
美国社会学家Herbert Blumer 布鲁默 (1900——1987),是自我互动理论的提出者,他认为, 人是拥有自我观的存在,人将外界事物和他人作为认识对象的同时,也会把自己本身作为认识的对象。
过程中人能够认识自己,拥有自己的独立观念,与自己进行沟通或传播时,也能要求自己采取行动。
这种与自身的互动方式,称之为—— “自我互动”,在本质上来说是与他人的社会互动的内在化,也就是与他人的社会联系或“关系”在头脑中的反应。
还是那个故事,你在地铁上准备吃韭菜馅包子,但是转念一想这么多人,我吃了后会不会有味道而影响到大家,可自己又想吃,于是内心就会形成两种对话。
第一种:不管了我很饿,我就是我不一样的烟火,别人怎么看不重要。
第二种:我这种大公司工作有品位的人,在地铁上做这种事情确实有点大俗大雅,还是遵守社会价值观,维护良好形象,下地铁再吃。
在自我互动过程中大脑中会出现他人和社会期待,犹如吃包子的场景,而个人会以自己的立场或“行为方向”对他人的期待进行能动的解读,加工,选择,并在此基础上重新组合。
然后重新创造出于新情况相适应的新意义或者行为,经过这个过程的他人期待已不是原来意义的他人期待,所形成的自我也不在是原来意义上的自我,而是一个新的主体。
不过,自我互动并不是与他人的社会互动在大脑中的简单出现,而是 具有独自的特点,比如每一次“主我与客我”对话中会触发人的内省式思考。
什么是内省思考(reflective thinking)?日常,短期高效以解决现实中制造的冲突问题为目的的自我反思。
譬如当你在众人中吃韭菜盒子,众人捂鼻的动作,当你在1000人大会演讲中不小心念错人名等。
当遇到紧急困难或障碍时大脑就会活跃起来,以至于对解决新问题,适应新情况来调整自身, 横向看内省式思考不是呈现为封闭状态,它是与周围环境,社会过程传播的联系。
内省过程中,个人会分析和推测别人是如何思考的,进而形成自己的态度轮廊,因此这个过程是重构自我与他人关系的过程。
从纵向看,它会将过去,现在联系起来,个人会把迄今为止有关的知识积累,保存在头脑中的记忆信息全部调动起来,然后对遇到的事情,人,进行解释,强化,在此基础上创造与新状态的特征。
所以当我们遇到某件新鲜事,约见一个新朋友时,你看他长相穿着的第一眼开始,大脑就会摄入信息,接下来“自我与客我在心中博弈处理”,激发内省,最后自我互动,以偏概全,出现基础标签画像。


02

基本归因处理法


除上述外,那么内省式思考,自我互动为什么会让自己“以偏概全”呢?这也和 “基本归因”有很大关系。

 

基本归因分为正确,错误两个方面,科普中国百科定义为人们在考察某些行为或后果的原因时高估倾向性因素,低估情景因素,譬如谴责或赞美他人的双重倾向(Lee Ross, 1977)。


定义是不是有点复杂?那么我们简单理解:


我把它解释为 “你对事件原因”的判断,生活中多数用到的是对自己成功或失败的归因,但除这些外别人的行为也可能成为我们归因的目标。


为什么会有归因偏差?


先带你做看一个简单实验,请你想象下这种场景,你在马路上开车遇到红绿灯等待,刚好红灯转绿,正准备启动的同时突然从后方出来一辆摩托车,抢到你前面,吓得自己出一身冷汗。


这种情况你会有什么反应?大多数人肯定愤怒的内里说出了脏话,此时你对那位司机印象以及行为极度不满,并在内心给他贴上一系列标签,譬如“行事莽撞”“安全意识差”“不考虑别人”等。


虽然你可能还没有见过此人,但在内心已经做出基础判断,不过现实中,一辆车横冲而过必有其原因,可能司机的确鲁莽,但也可能是因为有急事处理,比如“要去医院”。


更多可能性却让我们忽略掉,最终把原因归属到对方这个“人”身上,这种倾向心理学就是 “基本归因错误”。


日常中各种现象你也会遇到,譬如工作中销售业绩不佳时,领导更倾向于将其原因归属于下属的懒惰而不是竞争对手的实力太强。


譬如我的眼睛天生有色弱缺陷,看红绿灯没问题,对浅红和浅绿分不清,但我家人从来都不让我开车,一是为了安全, 其次就有极大的“归因错误”,不能因为某件事的判定而直接决定整体。


归因错误的核心在于人是“认知经济学家”不是“朴素心理学家”,而这一切就好比经济学总是假设“民众都是最严格的经济动物”这个观念是错误的一样。


心理学以前也出现过假设大家都是“朴素心理学家”的观点,即普通人也会用心去观察并分析人们解释问题,分析成功原因时,着重分析出哪些因素,并研究其中的道理。


然而并不一定所有人都是认知经济学家,因为人的大脑本能总是懒惰的,谁愿意去思考那么多,挑就近原理, 容易的不好去决策不好吗?


譬如, 这种场景你上学时或许遇到过:


三长两短选最短,三短一长选最长,两长两短就选B,同长同短就选A,长短不一选择D,参差不齐就选C,以抄为主,以懵为辅,抄辅结合,定能及格。


现在想想这是不是一种荒谬的“归因偏差”,所以归根到底偏差的核心在于懒得思考,脑中逮住旧有认知就转移成为了语言,却不知道其原认知接受的信息是否有“依据”,是否正确,最后机会产生“晕轮效应”发生。


为什么第一信息很重要?


墨菲定律中有这样一则故事,1974年,希伯来大学心理学教授卡纳曼和特沃斯基做了一个实验。


实验要求志愿者对非洲国家在联合国所占席位的百分百进行评估,首先他们随机给出每组志愿者一个百分比数字,然后他们逐个暗示志愿者真实数字比这个大或小。

 

有趣的是, 志愿者最后预估出来的数字,都受到一开始随机数字的影响,比如实验中志愿者得到的实验数字分别是10%和60%,而他们最终估计出来的数字分别为25%和45%,非常接近这两组志愿者一开始得到的随机数字。


这个实验得到的结论为:


人们在决策之前,思维往往会被所得到的第一信息所影响,它就像沉入海底的锚一样,把你的思维固定在某处,从而产生先入为主的歪曲认知。


还要一个非常经典的故事,说有一家卖三明治的小店,店里有两名售货员,其中一名每个月的销售业绩都要比另外一名高,老板就觉得非常郁闷。


有一天他躲在门后观察两位销售的区别,才发现,每当顾客点餐时,一名销售员说,先生(小姐)您需要加一个鸡蛋还是两个? 顾客经常在一和二中选择,只有不到30%的消费者选择不加。


而另一名销售员则是询问顾客,先生(小姐)你需要加鸡蛋吗?顾客的思考范围被锚定在“需要还是不需要加鸡蛋”上面,只有少数人想到加二个上面。


其实在现实生活中还有很多案例,譬如你去咖啡厅或奶茶店会被问统一问题,要大杯还是超大杯?


曾经我脱口而出要中杯,店员礼貌的告诉我:“不好意思,我们没有中杯”,他们真没有中杯吗?


其实我们熟悉的星巴克,部分门店确实只配备大杯,超大杯,但是他们为了销售额的增加,故意把“中杯给隐藏”作为锚定,从而推荐超大杯,引导你去决策。

 

这些种种情况告诉我们:


人的第一印象一旦形成,便会导致认知懒惰和惯性思维,那些善于利用这种心理的人,就会先发制人,所以如果是初次见面认识一位朋友,你给他提供的一手信息 (形象,颜值,穿着,谈吐)很重要。




03

大脑为什么会误判


当我们认知到第一信息的重要性直接影响“归因”的正确和错误,除此以外,大脑也会给我们开玩笑, 让我们对信息产生误判。
除对人印象以外,从对事层面不妨来思考下,你接触的第一信息就一定正确吗?其实未必。
你所经历的缪氏错觉
以色列裔美国心理学家丹尼尔·卡尼曼(Kahneman )用缪氏错觉(Müller-Lyer illusion)打了个比方。
《缪氏错觉(Müller-Lyer illusion)》

如上图所示这三条线是不同的平行线,A,B,C箭头依次代表不同方向,因为箭头朝向关系大小不同,你所看到的效果也不同,如果我第一时间问你哪个最长,我想你肯定会毫不犹豫的说中间那条, 但实际上它们三者是一样长。
那么问题的关键是什么呢?

即使我们用直尺测量这三条线,知道它们一样长,并且也了解这种环节背后的神经原理,但在我们眼中,A依然比其他两者要短些。



在比如上述这张图, 你第一直觉看到的是侧脸还是正脸的一半呢?


惯性思维肯定回答的只有“正脸或者侧脸”,而当你真正冷静下来时会发现其实是两者兼容的图片。


在经历视觉幻觉时,我们行动缓慢的但又善于分析的大脑,能够意识到缪氏错觉并说服大脑不要相信靠直观感受的结论,但现实生活中,当我们碰到活生生案例时,一切就不那么容易了, 这也就是所谓的认知偏差。

 

喜欢分歧与美丽困境


除视觉上的认知偏差,还有两条人际交往中的认知偏差也会让你产生“晕轮效应”,分别为 美丽困境(Beautiful mess effect)与喜欢分歧(Liking Gap)。


何为美丽困境(Beautiful mess effect)?


生活与工作中对于多数人来说,承认错误寻求帮助,甚至承认自己喜欢某个人,都是件很难开口的事情,为什么?因为暴露弱点或弱点会让人处境相对弱势,我们担心被拒绝,我们担心被拒绝后的“评判”而无颜面存在。


而现实中据资料记载研究者Anna Bruk与团队做了次试验,要求参与者想象别人和自己展示脆弱的场景,然后分别作出评价。


随后在另一项研究中,研究者设计特定场景引发参与者真实展示自己的脆弱或弱点,结果都发现,参与者对自身脆弱的评价都比别人的评价更消极,别人甚至会觉得展现自己的脆弱是一种勇敢的行为。


这就是看似矛盾的现象,虽然自己不想暴露脆弱,但我们对那些坦诚自己脆弱的人,却持有积极的态度,这也是所谓的“认知偏差”。


为什么会有这种情况呢?


“解释水平论”(construal level theory)解释了这个现象,原因是当我们思考自身脆弱时,因为对自身的了解,就会思考很多细节,使这件事暴露在外成为件格外丢脸的事情,就会使处境难看。


我们更关注细节和事情本身, 就会很少做进一步意义上的解释或本质的思考,但相反,对于别人的脆弱,我们的感性脑会更加抽象,不会停留在具体情境和行为上,还会更加抽象客观的理解事情的本质。


何为喜欢分歧(Liking Gap)?


你和别人第一次见面,如果别人特意打扮,自己并没有收拾匆匆忙忙而过去在加上不是太熟,很多人就会觉得焦虑,从而就会造成我们消极的判断,譬如:“他不会不太喜欢我把”“我刚才似乎不应该说那句话”等。


这种判断其实就出现了认知偏差,我们低估了对方对自己的判断,就会产生喜欢分歧(Liking Gap)。


研究者Erica Boothby(2018)在耶鲁大学进行试验,他们让两个同性别陌生人见面自然聊天,然后评估自己对彼此的喜爱程度,以及对方会多喜欢自己。


结果发现,他们都低估了对方对自己的喜爱,并觉得以后有机会,对方可能也不会跟我再次讲话。


其实这种现象很普遍,有人认为对方态度捉摸不定,才让我们判断错误。


但结果比较出人意料,并不是因为对方没有释放相关讯息,而是即使讯息存在,我们依然会关注那些自我批判的想法, 有偏差的关注点就会造成不准确的认知出现。




04

如何防止归因偏差


了解这么多,让我们拨开迷雾见太阳,晕轮的背后核心其实 “归因偏差”与“认知偏差”占大比例权重,而两者直接会让我们“以偏概全”。
其实世界不存在所谓的正确归因,我们只能 做到方向大致正确偏差概率很小,那么如何有效解决呢?
(归因之父)德国格式塔心理学家弗里茨·海德,Fritz Heider是最先研究归因的问题,他认为,最常见的归因有两种模式,一种是外部归因,又叫做“情景归因”,另一种叫做“内部归因”,也叫做性格归因。
什么是内部归因?
个人的能力,个性,情绪,努力,态度或性格导致一个人做出的某些行为,我把它统称为行为与后果的发生是由个人特征造成的。
什么是外部归因?
周围环境,他人,或者不可知的力量,比如运气导致某种结果的产生,比如总有人把“大环境不好”挂在嘴边,就属于外部归因,大环境不好其实更有机会点。
成功的人与失败的人本质就在于“归因”不同,除环境,运气之类客观条件之外,他们对此生所经历的所有事的不同归因也会影响是否成功。
所有成功者的归因常常是积极乐观的,而失败者的归因往往是消极悲观,最后形成一种 习惯性无助(Learned Helplessness)。
美国心理学家罗德·凯利(Harold Kelley)觉得这个理论挺好,但过于简化了,他便提出了“三维归因”,又称“协变模式”,它的核心思想为:
我们都倾向于用充分条件,必要条件这些内在逻辑来认知世界和他人,它认为,我们会收集各种信息来做归因,比如“时间,地点,自身,参与者,情境等”。
《三维归因》
其中有三个维度是我们常用的:共识性Consensus,特殊性Distinctiveness,一致性Consistency 
共识性指不同人面临同样情境,行为表现是否和所观察保持一致。 特殊性指观察对象对于不同情境是否表现不同,对于同类情况表现是否不同。 一致性指不同时间,地点情境,面对类似刺激时,同一个体表现一样吗?
举个例子:


你看到一个经理在批评员工,你觉得经理有问题还是员工有问题?


如果不只是经理批评他,而是客户和其他员工也在批评他, 这就是高共识性,如果经理一般不批评员工,只批评了他, 这是特殊高共识性,若经理有事没事就批评他, 这是一致性共识性。


在上述中可得出结论,不是经理人品有问题,而确实是员工有问题。


那么情况反过来呢?


除了经理,其他人并没有批评过这个员工,这就是 共识性低,经理哪个员工都有事没事批评,这是 特殊性低,经理常常批评这个员工,也就是一致性高,那么人们会倾向于 “老板人品有问题”。


以上这种情况,若一致性低,不管共性和特殊性的高低,人们都很难做出准确归因,会产生一种不确定感,或者会选择其他外界归因,比如人们常听说的 “领导今天可能心情不好”,离他远点。


那么怎么办呢?也就有了 对应论的出现,一般思考基于三个假设:

 

其一:行为者预先知道一个行为的结果。

其二:行为者有能力做出此行为。

其三:行为者想要的就是这种结果。


譬如你去揭发一个人的心灵伤疤,对方恼羞成怒,这里你的行为就符合上述三个假设,我们也可以顺利归因,你就是想让他恼羞成怒。


那么如何提高自己归因的准确性呢?


其一:对应推理归因,如果一个观察者所拥有的信息越多,他对该行为所做的推论对应性就越高,也就是归因月准确。


第二:一个人行为越是异常,观察者对归因的准确性也就越大。


举个例子:你对爱人的行为判断往往比同事对他的判断要准,这是因为你对你爱人更加了解。


再比如当你老板骂你时,多数人都会做出虚心接受的样子,而这个 “虚心接受”到底是接受了还是委曲求全,其实很难从表达判断,因为你一般不会反驳老板。


但假如你马上朝老板身上泼了一杯水,这时就很明确你很生气,对他意见很大,也不在乎这个工作了。




05

360度认知事物


那么除了 内外归因,三性(特殊性,共识性,一致性)部分外,还有没其他因素影响我们归因呢?
当然有, “影响对推伦”解释了这一切,如果你能把这五个方面融合,相信更能在事物中找到准确性。
影响对推伦的五个要素
第一:非常见效果Non-Common Effect
这里指一个人的行动不同于常见方案,譬如你站起来走到窗户前去关窗,并穿上外套,由此推断天气凉了,若只是关窗,也可能是因为外面太吵,因此只管窗很难推断原因, 而穿毛衣就非常显著的确认“归因”。
第二:低社会可取性(Low Social Desirability)
当一个人表现出符合社会期望行动时,我们很难推论出他真实的态度,譬如上述中你对老板的“虚心接受”,这是符合期望的。
但当一个人行为不符合期望时,如当老板无理问责,你忍无可忍泼水的动作,那么这个行为与你的真实态度就相对于,老板和同事就都会明白。

 

第三:社会期望(Expectancies)


主要分为社会阶层期望和个人期望,比如资本家与农民工,他们在任何一个人社会新闻中表现都是不同。


例如贫困家孩子被北大和一所职业专业录取了,那么他若去了北大,我们希望能改变命运便可理解,但若他去了本地专科,我们就会觉得他没钱,但如果一个中产家庭遇到这种场景,我们便无法解释了。


第四:选择自由(Choice)


行为处于自由选择,而非外力强迫,我们更倾向于认为某个行为与态度是相对应的,比如一个孩子上大学前很努力,我们很难判断他因为爱学习,还是因为家长外界释放压力。


但若他到了大学家长的外力消失了,他依然很努力,那么我们就可以归因 “他真的爱学习”。


第五:个人参与度(Personalism)


我们对被观望的对象的态度是什么?有时是因为喜欢或者讨厌,就会对他的行为有更积极或更消极的解读。


比如你和某个伙伴的关系不错,你夸她时更像赞美,但你如果和他关系不好,猛然一夸,会让人觉得你不怀好意。


基于这5个要素,我们就构建基础的“影响对推论”,你可能会觉得这样分析很有道理,不过太机械和静止看待问题。


美国心理学家伯纳德·韦纳(Bernard Weiner)也是这样认为,最后它基于上述提出 “动态三维模型”,来解释。


什么是动态三维模型?


一个人对于某些事物成败的归因,会反过来影响参与这项活动努力的程度,而一件事结果的好坏,也会加强或削弱对这件事的归因。


举个例子,我认为我能完成这个任务,是因为做过且有把握,于是我对未来完成此类任务充满信心,下次遇到你还会这样, 这就形成一个行动和想法的良性循环。


韦纳教授把这个成就归属分为三个维度,这三个维度也包含相反的一面,分别为:


第一维度:稳定性(稳定与不稳定)

第二维度:控制源(内部控制和外部控制)

第三维度:可控性(可控与不可控)


 《影响对论与动态三维》


理论总是比较抽象, 我们看一则故事:


小时候我们经常说孩子考试考的真好,有时却很差,到底什么因素会影响成绩呢?有很多,比如考试的难度,孩子努力的程度,运气等等。


现在我们进行分类归因, 有些因素是稳定的,比如考试难度和孩子智商,有些则是不稳定的,比如努力程度,考试运气等。


有些因素是内部控制源的,比如努力程度,有些是外部控制源,比如难度和运气,那么可控的是什么?依然是努力程度和考试难度, 不可控的呢?运气,智商。


所以对于一个成功者来说,理解什么是稳定,内部可控,可以帮助他接受自己的基础上增强信心,理性的进行归因。


若把不稳定外界因素,不可控因素都归因为稳定,内部及可控因素,当这些汇总结果成为正面时,会让人积极快乐,但可能会让人偏离现实,做错误的归因。


所以 “归因风格会影响一个人的动机”。


我们会发现成功者归因往往会认为能力优秀,他们觉得自己能控制进程。


若任务失败,成功者会归因于外界因素,比如团队不行,事出偶然等,你这么一听, 可能会觉得成功也不怎么样,不谦虚,不客观。


不过你要注意的是,他们不一定是正确的,但这些归因给了他们继续挑战的动机和信心,反之失败者,不论事前事后,都觉得自己能力不行,即使偶然成功,也是运气而已。


分享给你一段话:


这三句话来自于美国一位神学家尼布尔,他说: “神啊,求你赐给我一颗宁静的心,去接受不能改变的事。


求你赐给我信心和勇气,去改变能改变的事。神啊,赐给我智慧,去分辨两者的不同。




写在最后:


让我们回顾一下,容嬷嬷,纪晓岚, 和珅形象在人的心智中怎么来的?


大脑接受信息—内心“主客我心理定夺”——基本归因——思维沉抛——强化塑造——形成固化标签。


所以人的第一印象重要吗? 非常重要。


了解晕轮效应后,从人物与事实角度,你会如何做归因呢?


大脑接受信息—内心“主客我心理定夺”——基本归因——思维沉抛——内部外部场景区分—匹配5要素— 再次归因— 强化塑造——形成标签。

 

你在别人眼中的每个场景,对方眼睛都会像卡尔蔡司镜头一样拍摄下来,回传至脑中形成记忆,不断打碎强化。


所以社交场合不管是见客户还是约会,稍微打扮一下, 衣着整洁,谈吐清晰,会让你的整体形象在对方的心智里加分。


当然从日常做事中,若遇到问题,也不要 以偏概全,归因于外界,从事实出发,向内求,别回头,向前看,多听批判的话加以思考, 祝你独具慧眼,明鉴万里。



部分关键文献参考:

1.新闻传播学:美国心理学家G.H.米德“主我与客我”理论

2.社会心理学家罗斯(LeeRoss)归因偏差

3.丹尼尔·卡尼曼(Kahneman )思考快与慢缪氏错觉

4.解释水平理论,社会心理学理论(Dhar & Kim ,2007)

5.格式塔心理学家弗里茨·海德(FritzHeider)归因理论


《加入星球,领取资料》
《幸会社介绍》:基于信任打造的链接型平台, 幸会社(XINGHUISHE) ,关注新品牌营销,私域增长,个体认知跃进,探索未知边界,寻找向上生长的力量。
在这儿,你还可以和伙伴相互监督,彼此进步,我们希望你能有 爱好分享的精神,而不是 一味的索取,现在, 幸会社已经有两个付费群,已经有近1000名+志同道合的朋友了,他们都是拥有“向上成长的精神”,等你加入,记得见面说声: “幸会,幸会”。


近期推荐







 个人号 

语言是这么不靠谱

我们却由着“语言”来决定一切。



觉得有价值,欢迎点个在看,每个人都应该拥有独立思考的能力,欢迎分享给更多人。

轻松配置react native热更新 - 简书

$
0
0

react-native项目有个优势就是可以动态更新bundle.js,从而更新App。

1.gif

项目代码传送门

框架选择

  • 使用微软出的热更新套件 react-native-code-push
  • 框架包括客户端SDK,以及配套的服务端。

服务端配置

  • 要使用 code push服务,必须在服务端配置好 app的信息。
  • 安装 App Center CLI,用于服务端信息管理。
$ sudo npm install -g appcenter-cli
  • 登陆 app cetner
$ appcenter login
  • 运行以上命令并在命令行确认后,网页会弹出一个要求登陆的页面,登陆后,会得到一串 Access code,复制粘贴回命令行,成功的话会返回登陆账号。
$ appcenter login
Opening your browser... 
? [Visit]:https://appcenter.ms/cli-login?hostname=assetfundeMacBook-Pro.local and enter the code:
? Access code from browser:  0cd185da****36a****7295b3****c8da9ba766a
Logged in as kk412027247
  • 添加 App信息,这里要分别添加 安卓iOS,我的 app名字是 splashExample,以此为例
// -d 后面接的是app显示的名字,为了区分不同平台后面也写上平台命
// -o 表示运行系统(operation) 安卓/iOS
// -p 表示平台(Platform)这里是 react-native
$ appcenter apps create -d splashExample-android -o Android -p React-Native
$ appcenter apps create -d splashExample-ios -o iOS -p React-Native
  • 接下来运行一下 appcenter apps list检测是否添加成功
$  appcenter apps list
  kk412027247/splashExample-android
  kk412027247/splashExample-ios
  • 将已添加的 app部署热更新服务,一般会部署两个用于灰度更新,和正式更新,这里分别叫做 StagingProduction。分别给安卓和iOS部署,所以一共要运行四行命令。

建议部署其中一个叫做 Staging,命令行一些默认行为会执行这个部署,如果没有这个名称,推送更新到部署的时候,要指定部署的名称,若不指定则会报错。

// -a 是指应用(application),这里要写上“用户名和程序名”

// 部署IOS
$ appcenter codepush deployment add -a kk412027247/splashExample-ios Staging
$ appcenter codepush deployment add -a kk412027247/splashExample-ios Production
// 部署安卓
$ appcenter codepush deployment add -a kk412027247/splashExample-android Staging
$ appcenter codepush deployment add -a kk412027247/splashExample-android Production
  • 获取 部署码,运行以上命令之后,命令行会返 部署码,但是有可能没记下就关掉了命令行
  • appcenter codepush deployment list -a <ownerName>/<appName> <deploymentName> -k命令可以查看部署码
$ appcenter codepush deployment list -a kk412027247/splashExample-ios -k
NameKey
StagingmgqluuNp1DTWNA5xn_c2YWWyLKGxBJA67O7UN
ProductionmiDM42DG-ooHvW0VVa0tdPNAgRH2BJJ6j_X8V
$ appcenter codepush deployment list -a kk412027247/splashExample-android -k
NameKey
Staging2CFJps8zo4gguRDddWp7POP0psZCrJnAXOQIE
ProductioncskcQEjzC5kbOelsPgwA4zaDac6SS1ow0tQIV

运行了一堆命令,最终得到这两组四个 部署码,接下来须要将这些 部署码按需配置到客户端里面。


客户端安装与配置

  • 安装依赖包
$ npm install --save react-native-code-push
$ react-native link

运行 react-native link的时候,命令行会提示输入部署码 What is your CodePush deployment key for Android (hit <ENTER> to ignore),这个提示只是第一次输入有效。

  • 填写 部署码,我这里都是输入 Staging部署码。如果是正式环境,建议写 Production部署码

    • iOS平台,修改 /splashExample/ios/splashExample/Info.plist文件, CodePushDeploymentKey标签的值。
      iosDeploymentKey.png
    • 安卓平台,修改 /splashExample/android/app/src/main/java/com/splashexample/MainApplication.java
      androidDeploymentKey.png
  • api调用(安静模式)

import CodePush from "react-native-code-push";
// 静默方式,app每次启动的时候,都检测一下更新 'ON_APP_RESUME'
const codePushOptions = { checkFrequency: CodePush.CheckFrequency.ON_APP_RESUME };
import _App from './App';
// 在组件根节点的地方设置热更新。
const App = CodePush(codePushOptions)(_App);
  • 这个安静模式是我最喜欢一种,配置简单,在用户没察觉的情况下就更新了app。在用户打开app的时候,自动下载更新包,下次再启动的时候自动安装更新包。


    0.gif
  • api调用(自定义模式),在更新之前可以获取更新包的大小,更新的具体信息,监听下载进度等等。

import CodePush from "react-native-code-push";
...

  state = {receivedBytes : 0, totalBytes : 0, showProcess: false, showIndicator:false};

  _handleUpdate = async () => {
    this.setState({showIndicator: true});

    // checkForUpdate 返回promise,包含了服务端安装包的各种信息,包的大小版本之类的,
    // 如果要构建构建个性化更新界面,需要用到此方法
    const updateMessage = await CodePush.checkForUpdate() || {};

    // console.log(updateMessage);
    // return;

    // 执行更新
    await CodePush.sync(
      // 第一个参数吗,是个对象,可定义更新的动作
      {
        // 安装模式 'IMMEDIATE' 立刻安装, ON_NEXT_RESUME 下次启动安装
        installMode: CodePush.InstallMode.ON_NEXT_RESUME,

        // 强制更新模式下的安装,默认是IMMEDIATE 直接安装
        mandatoryInstallMode: CodePush.InstallMode.IMMEDIATE,

        //更新确认弹窗设置,设置系统自带弹窗中的内容
        updateDialog:{
          mandatoryUpdateMessage:'强制更新内容: '+updateMessage.description,
          mandatoryContinueButtonLabel:'强制更新/确认',
          optionalIgnoreButtonLabel:'取消',
          optionalInstallButtonLabel:'安装',
          optionalUpdateMessage:'本次更新内容: '+updateMessage.description,
          title:'发现新版本'
        }},
      // 第二个参数,更新状态检测,返回数字
      //0 已经是最新,1 安装完成、等待生效,2 忽略更新,3 未知错误,4 已经在下载了,5 查询更新,6 弹出了更新确认界面,7 下载中,8下载完成
      (status)=>{

        switch (status){
          case 0: alert('已经是最新版本');
            break;
          case 1 : !updateMessage.isMandatory && alert('更新完成, 再启动APP更新即生效');
            break;
          case 3: alert('出错了,未知错误');
            break;
          case 7 : this.setState({showProcess: true});
            break;
          case 8 : this.setState({showProcess: false});
            break;
        }
      },
      // 第三个参数,检测下载过程
      ({receivedBytes,totalBytes})=>{
        // console.log('DownloadProgress: ', receivedBytes, totalBytes);
        this.setState({receivedBytes: (receivedBytes/1024).toFixed(2), totalBytes: (totalBytes/1024).toFixed(2)})
      },
    );
    this.setState({showIndicator: false});
  };

  handleUpdate = () => this._handleUpdate().catch(()=>{
    this.setState({showIndicator: false});
    alert('网络错误')
  });
  • 这个配置稍微复杂一点,但是自定义程度很高,比如要做下载滚动条,查看更新日志,都可以实现。默认情况下,再次启动app的时候,更新生效。


    1.gif

推送更新

设置完客户端之后,须要在服务端推送更细,客户端才能检测到更新。以上效果都是已经从服务端做了更新推送的。

  • 推送命令,在项目根目录运行 appcenter codepush release-react -a <ownerName>/MyApp
//  在默认情况下,更新会推送到Staging的部署
$ appcenter codepush release-react -a kk412027247/splashExample-ios
$ appcenter codepush release-react -a kk412027247/splashExample-android

//  指定版本更新 -d 加部署名
$ appcenter codepush release-react -a kk412027247/splashExample-ios -d Production
$ appcenter codepush release-react -a kk412027247/splashExample-android -d Production

// 设置更新日志,供前端读取
$ appcenter codepush release-react -a kk412027247/splashExample-ios  --description '1800的更新'
$ appcenter codepush release-react -a kk412027247/splashExample-android  --description '1800的更新'
  • 强制更新,在项目根目录运行 appcenter codepush release-react -a <ownerName>/MyApp -m true
  • 其实就是多了个 -m true参数而已,强制更新的默认效果是,用弹窗确认更新时候,只有确认键,并且安装成功后是立即生效,所以app可能会闪一下。
$ appcenter codepush release-react -a kk412027247/splashExample-ios -m true  --description '1052的更新'
$ appcenter codepush release-react -a kk412027247/splashExample-android -m true  --description '1052的更新'
2.gif
  • 查看更新看历史 appcenter codepush deployment history -a <ownerName>/<appName> <deploymentName>
// 显示历史
$ appcenter codepush deployment history -a kk412027247/splashExample-ios Staging

// 清空历史
$ appcenter codepush deployment clear Staging -a kk412027247/splashExample-ios

官方资料

React Native Client SDK安装与配置
App Center CLI安装与配置
js api


项目代码地址

给我一个 babel,还你一条完整前端工具链

$
0
0

你不知道的 babel

提到 babel,你会想到什么?

  • 可以把项目中的 es6、es7 等代码转成目标环境支持的代码
  • 可以自动 polyfill 目标环境不支持的 api
  • taro (小程序转译工具)是基于 babel 实现的
  • babel 的插件很丰富
  • 我们公司现在用 babel 来编译 typescript,不用 tsc 了
  • 我基于 babel 做过自动埋点的功能,得到了领导的夸奖
  • ...

其实 babel 能做的不只是这些,它能做 3 类事情:

转译 esnext、typescript、flow 等到目标环境支持的 js

这个是最常用的功能,用来把代码中的 esnext 的新的语法、typescript 和 flow 的语法转成基于目标环境支持的语法的实现。并且还可以把目标环境不支持的 api 进行 polyfill。

babel7 支持了 preset-env,可以指定 targets 来进行按需转换,转换更加的精准,产物更小。

一些特定用途的代码转换

babel 是一个转译器,暴露了很多 api,用这些 api 可以完成代码到 AST 的 parse,AST 的转换,以及目标代码的生成。

开发者可以用它来来完成一些特定用途的转换,比如函数插桩(函数中自动插入一些代码,例如埋点代码)、自动国际化、default import 转 named import 等。

现在比较流行的小程序转译工具 taro,就是基于 babel 的 api 来实现的。

代码的静态分析

对代码进行 parse 之后,能够进行转换,是因为通过 AST 的结构能够理解代码。理解了代码之后,除了进行转换然后生成目标代码之外,也同样可以用于分析代码的信息,进行一些检查。

babel 还能做什么?

babel 是前端业务开发和工具链开发中必不可少的工具,我们每天都在用,可是你有想过这些问题么:

  • 怎么写一个 babel 插件来做自定义的代码转换?
  • 业务开发中有哪些地方可以用 babel 来做自动化?
  • babel 是怎么实现的?

还有

  • linter 是怎么实现的?
  • typescript 类型检查是怎么实现的?
  • 压缩混淆工具的原理是什么?
  • 打包工具是如何分析代码依赖关系的?
  • api 文档如何自动生成?

上面这些都可以用 babel 来实现,或许你并没有想过 babel 有这么大的能量, 学会了 babel,绝对能让你提升一个段位

基于 babel 实现完整工具链

我们来理一下这些工具的实现思路(所有下面列的工具都有 实现代码放在 github)

自动国际化

国际化是把写死的字符串字面量换成从资源包取值的方式,babel 可以分析出代码中的字符串字面量,把它替换成一个函数调用语句,然后自动引入资源包。基于 babel,我们完全可以做到自动国际化。

自动生成 api 文档

我们在写 api 的时候,会在上方添加注释,那么是不是能把这些注释内容还有关联的函数、class 的信息提取出来,用一定的模版来生成 api 文档呢? 没错,babel 可以做到。

linter

我们整天用 eslint、stylelint 来做代码规范的检查,其实他们不过就是对 AST 做了校验,这些我们用 babel 完全可以做到。可以基于 babel 实现 eslint。

type checker

typescript 是给代码添加了静态的类型信息,可以在编译期间进行类型检查,也可以辅助做代码的智能提示,现在基本是前端必备技能了。可是你有想过 typescript 怎么实现的么?在小册中 我们会手写一个 ts type checker,让你真正理解 typescript!

压缩混淆

前端代码上生产肯定要做压缩,做混淆,这个我们整天都在用,可是你知道他的实现原理么,我们能不能用 babel 来实现一下。答案是肯定的,在 小册我们会实现压缩混淆的功能

js 解释器

v8 引擎的实现原理是什么,解释型语言都是怎么解释代码的。我们能不能实现一个 js 解释器,是可以的, 《babel 插件通关秘籍》小册中我们会基于 babel parser 实现一个 js 解释器。

手写 babel

可能你会问,上面的这些都是基于 babel,那如果没有 babel 呢?

没有 babel 我们就实现一个 babel, 小册最后 我们会实现一个简易但可用的 babel,让你真正理解 babel 的原理,真正掌握 babel

上面的解释器和类型检查的内容, 王垠卖 12000,见下图,所以这本小册绝对超值。

大纲

上面说了很多小册的内容,下面是小册的完整目录:

不只是 babel

虽然上面的实战都是基于 babel 的,可是你学到的只是 babel 么?

不是的,上面的实战案例涉及到完整的工具链,从文档生成、lint、type check、压缩混淆到 js 解释器等等,这几乎是前端开发的闭环了。 以此为抓手,学到的是整条工具链的实现思路

上面的工具还是集中在前端领域,但其中转译器、解释器的实现思路确是通用的,编译原理主要就是学编译器、转译器、解释器三部分, 学完整本小册,相信也能帮助你入门编译原理

总结

babel 是前端领域几乎是必备的工具,基于它可以完成很多功能,甚至是打造整条工具链,我们在 小册中会实现 linter、type cheker、压缩混淆、api 文档自动生成、js 解释器等等一系列功能。其中解释器和类型检查的功能在王垠那里能卖 12000,对比之下,这本小册内容和价格绝对很良心了。

如果说 babel api 是术,那么基于 babel 学到的编译原理、工具链实现思路就是道了。掌握了 babel、掌握了工具链,入门编译原理,绝对能让你提升一个段位。


数据仓库系列之元数据管理 - 简书

$
0
0

    元数据(Meta Data),主要记录数据仓库中模型的定义、各层级间的映射关系、监控数据仓库的数据状态及 ETL 的任务运行状态。一般会通过元数据资料库(Metadata Repository)来统一地存储和管理元数据,其主要目的是使数据仓库的设计、部署、操作和管理能达成协同和一致。元数据是数据仓库管理系统的重要组成部分,元数据管理是企业级数据仓库中的关键组件,贯穿了数据仓库的整个生命周期,使用元数据驱动数据仓库的开发,使数据仓库自动化,可视化。

    构建数据仓库的主要步骤之一是 ETL。这时元数据将发挥重要的作用,它定义了源数据系统到数据仓库的映射、数据转换的规则、数据仓库的逻辑结构、数据更新的规则、数据导入历史记录以及装载周期等相关内容。数据抽取和转换的专家以及数据仓库管理员正是通过元数据高效地构建数据仓库。


元数据

    用户在使用数据仓库时,通过元数据访问数据,明确数据项的含义以及定制报表。数据仓库的规模及其复杂性离不开正确的元数据管理,包括增加或移除外部数据源,改变数据清洗方法,控制出错的查询以及安排备份等。

一、元数据类型

​元数据可分为技术元数据、业务元数据和管理过程元数据。

1、 技术元数据为开发和管理数据仓库的 IT 人员使用,它描述了与数据仓库开发、管理和维护相关的数据,包括数据源信息、数据转换描述、数据仓库模型、数据清洗与更新规则、数据映射和访问权限等。

2、 业务元数据为管理层和业务分析人员服务,从业务角度描述数据,包括商务术语、数据仓库中有什么数据、数据的位置和数据的可用性等,帮助业务人员更好地理解数据仓库中哪些数据是可用的以及如何使用。

3、 管理过程元数据指描述管理领域相关的概念、关系和规则的数据,主要包括管理流程、人员组织、角色职责等信息。

二、元数据功能

1、血缘分析:向上追溯元数据对象的数据来源。血缘分析可以帮助您轻松回答:'我正在查看的报告数据来源是什么?'以及'对当前分析的数据应用了哪些转换处理?'等问题。这样的机制及对这些问题的回答确保了对所分析的数据更高的信任水平,并有助于实现许多行业(包括医疗、金融、银行和制造业等)对所呈现数据的特殊监管及合规性要求。

2、影响分析:向下追溯元数据对象对下游的影响。影响分析可以让您轻松应对变更可能产生的影响,自动识别与其相关的依赖项和潜在的影响还可以跟踪所有对象及其依赖关系,最后我们还提供数据全生命周期的可视化显示。例如,如果您的某一信息系统中准备将“销售额”从包含税费更改为不包括税费,则SE-DWA将自动显示所有使用了“销售金额”字段,以便您可以确定有哪些工作需要完成,并且建议您在更改前完成该工作。

3、同步检查:检查源表到目标表的数据结构是否发生变更。

4、指标一致性分析:定期分析指标定义是否和实际情况一致。

5、实体关联查询:事实表与维度表的代理键自动关联

三、元数据应用

1、ETL自动化管理:使用元数据信息自动生成物理模型,ETL程序脚本,任务依赖关系和调度程序。

2、数据质量管理:使用数据质量规则元数据进行数据质量测量。数据质量根据设定的规则帮助您过滤出有问题的数据,并智能分析数据质量缺陷。

3、数据安全管理:使用元数据信息进行报表权限控制。可以方便查看用户和访问权限,并启用对象级和行级安全管理。对象级安全性确保通过身份验证的用户只能访问他们被授权查看的数据、表或列,其它数据则不可见。基于行的安全性会更进一步,可以限制特定的组成员只可以访问表中特定的数据。

4、数据标准管理:使用元数据信息生成标准的维度模型。

5、数据接口管理:使用元数据信息进行接口统一管理。多种数据源接入,并提供多种插件对接最流行的源系统。应该可以简单方便获取数据。

6、项目文档管理:使用元数据可以自动、方便的生成的健壮全面的项目文档,其以帮助您应对各种对于数据合规性要求。读取元数据模型,并生成pdf格式的描述文件。生成文档您查看每个对象的名称、设置、描述和代码。

7、数据语义管理:业务用户在自助服务分析中面临的挑战他们不了解数据仓库从而无法正确解释数据,使用元数据可以语义层建模,使用易于业务用户理解的描述来转换数据。

四、总结

​    由上可见,元数据不仅定义了数据仓库中数据的模式、来源、抽取和转换规则等,而且是整个数据仓库系统运行的基础,元数据把数据仓库系统中各个松散的组件联系起来,组成了一个整体数据仓库解决方案。

基于CWM的ETL元数据库系统模型的设计

$
0
0
1 引 言

在工业领域,数据仓库连同前端的数据挖掘工具向企业高层提供决策分析的平台体系机制被称为商业智能(Business Intelligence,BI)。BI项目的实施牵涉到企业各个事务处理系统之间海量数据的定向流动,这个数据流动的过程被称为数据抽取、转换与装载(Extraction、Transformation and Loading,ETL),是BI系统的心脏与灵魂 [  1]。ETL过程的管理目标与其数据质量是密切相关的,高效的ETL过程管理可以在一定程度上预防和控制ETL过程中出现的数据异常,是保障ETL数据有效性的重要手段。但是,在数据仓库实施中,ETL过程的多个业务逻辑交流环节都是基于人-人交流模式的,或者是通过人-文档-人的形式进行信息传递。这样的管理方式与数据仓库ETL过程的实际运行情况及结果是脱节的,使得ETL任务维护繁杂,返工代价大。鉴于此,本文提出基于公共仓库元模型(Common Warehouse Metamodel,CWM)标准建立ETL元数据库,它能描述ETL过程业务逻辑及数据变换细节,以此来实现人机交流,从而实现对ETL过程具体细节的管理及分析。

2 相关研究综述

以CWM和ETL两个字段为关键字,在CNKI数据库里检索,结果得到6篇文章,年代主要分布在2005年至2010年。目前,基于CWM的ETL过程管理研究主要集中在以下几个方面:

(1)业务变更、高层汇总数据分析与实时业务结合的纵深数据分析、实时业务处理,快速定义并部署用户的多维查询,实现基于数据仓库的联机分析处理 [  2]

(2)元数据的集成与管理,解决元数据管理混乱问题,实现不同系统之间的元数据交换 [  3,  4,  5]

(3)数据的映射规则和转换规则 [  6]

(4)缩短数据仓库的开发工作量、缩短开发周期、降低项目实施的风险,提出标准的ETL [  7]

基于CWM的ETL管理目前主要应用于元数据的管理,而对于某些数据问题被特定用户发现后,如何找到问题发生的位置和原因,没有更深入的研究。

本文在ETL元数据库的基础设计了一个系统模型,包含业务规则的改变触发相应程序改动预警、ETL任务调度可行性分析、ETL数据流向图展示、数据质量问题溯源定位分析4种机制, 可以把ETL过程中的各种静态和动态信息“透明”地展示给数据仓库相关用户,增强ETL过程与用户之间的信息理解与传递,从而达到改善ETL过程管理质量的作用。

3 CWM标准及其相关包类的选择

CWM是一个开放的业界标准,用于数据仓库及业务分析领域,为元数据定义公共元模型和基于XML语言的交换格式,描述一个完整的数据仓库系统的所有组成部分。作为能描述各种数据源和数据仓库对象的元数据,CWM本身就是一个相当复杂的信息体系。为了便于理解和易于开发者实现,CWM标准将元数据按照不同的功能和不同的描述层次进行分类,共分为21个元模型包,并在元对象机制(Meta Object Facility,MOF)框架中对不同包中的类与关联进行阐述 [  8]

在MOF框架中,底层的对象模型层是支撑基于该层以上整个元数据标准框架的基础。越往上层,元数据描述的内容就越宏观,越面向数据仓库的业务和管理。每个包的下层中与其相邻的包类对其起相应的支撑作用。对象模型层通过UML1.3描述框架来表达,它由4个包类组成,依次是核心包、行为包、关系包和实例包。其中核心包被其他三个包所依赖,它也被称为MOF元元模型 [  9],定义了数据仓库中不同对象共有的属性和动作,并衍生出不同对象的子类。对象模型是由OMG组织以UML1.3规范标准进行表述的。

从CWM标准中的21个元模型包可以知道,位于某层中的元模型只依赖于位于它下层的相关元模型,故如何使用CWM标准应根据具体的问题域需求来选择相应的元模型包,建立满足需求的系统模型。实现和使用公共仓库元模型的一部分是CWM元数据标准一个很重要的特征 [  10],这也是OMG组织设计原则的用意。所以,只需要使用与ETL相关的问题空间那部分CWM元模型即可。

与ETL转换过程细节和转换执行记录相关的包类有关系型包、转换包以及仓库操作包。其中,关系型包描述了ETL过程的静态元数据,转换包描述了ETL过程的动态元数据(包括转换过程细节和映射细节),仓库操作包描述了ETL过程实例级元数据。因此对于本文用于ETL过程元数据的应用功能来说,这些元数据已经能足够描述ETL过程的具体细节。

4 ETL元数据库系统的UML模型
4.1 元数据库模型分解图

CWM标准中ETL的元数据可分为以下三大块:有关数据对象的静态元数据、有关ETL步骤和映射过程的动态元数据以及ETL实例执行记录元数据。以上的元模型包类给出ETL过程管理元数据模型框架。在其基础上,通过适当的裁剪与扩展,并添加基本属性和附加属性,得到系统的元数据库模型 [  11]图1图2图3给出了ETL元数据库这三个部分的UML图。

图1 数据对象元数据UML模型

图1中,表对象是查询集对象的超类,查询集是表对象的一部分。由于表属于已命名列集(NamedColumnSet),而查询集是没有名字的,CWM把它们都归类为Classifier的子类,这是基于整体元数据管理体系来考虑的。这一部分元数据模型对应于CWM标准中的关系型包。

图2 ETL步骤与映射过程元数据UML模型

图2中, CFM类表示一类非常特殊的转换映射关系。这种映射的一端是多个列,另一端是单列。在CFM类的属性中,“字段名”代表的是单列端,“Classifier列集”代表的是多列端,多列端的数据类型是一个对象,即数据对象元数据里面的Classifier类。CFM类中“是否为归并”属性是一个布尔数据类型,该属性逻辑若成立(归并)则映射规则为多列端到单列端,若不成立(拆分)则映射规则为单列端到多列端。这一部分元数据模型对应于CWM标准中的转换包。

图3 ETL实例执行记录元数据UML模型

在ETL执行过程中,有时需要查看ETL整个活动的执行是否正确,在这里将“TS优先级”作为ETL执行记录的一个属性。这一部分元数据对应于CWM标准中的仓库操作包。

4.2 元数据库模型集成图

图4用节点来代替各部分元数据中的类,用节点间的联系来表达三部分的集成逻辑关系。

图4 ETL元数据集成后的UML模型

(1)数据对象元数据与ETL过程元数据之间的关联发生在映射关系上。转换映射包中的CM(ClassifierMap)类的源表与目标表都是从关系型包中的Table类中而来,转换映射包中的FM(FeatureMap)类的源字段和目标字段来源于关系型包中的Column类。而转换映射包中的CFM类的列集与列则分别来自于关系型包中的QCS类和Column类。

(2)ETL过程元数据与ETL执行记录之间的关联。在TE表中,详细记录了每次ETL操作的执行情况,包括ETL活动编号、步骤编号、优先级、是否正在执行以及是否执行成功等。以转换活动类的TA编号属性与转换步骤类的TS编号从而使得TE与ETL过程模式元数据之间的关联性。

通过以上UML模型,可以得出实施元数据库的通用策略。每个类对应一个元数据表,相关的类间具有特定的联系,从而建立起面向ETL过程的元数据描述体系。

5 某电信公司的ETL管理
5.1 ETL过程管理系统模型构建

系统的构建从实施ETL元数据库模型开始,搭建描述某数据仓库ETL过程的系统架构 [  12]。但在具体实施时需结合具体情况分析,因它的属性往往还涉及到所用数据的粒度属性。如在电信部门,数据一般是按照某一月份和某本地网编号聚集,因此在ETL执行情况记录表里面必须加上这两个属性,以明确ETL实例执行情况所代表的时期和地方。

根据整个系统涉及到的数据,该系统结构依照ETL活动层——ETL元数据库层——ETL元数据系统分析功能层三层模式来构造。内部结构按照元数据库功能来划分,包括元数据库操作区和分析区。其中分析区包括ETL任务调度分析、主题性数据的数据流向图展示、数据问题溯源分析等,依照ETL的元数据库还可以进行更多的功能扩充,以便对数据仓库ETL过程进行多方位的管理。具体结构如 图5所示:

图5 ETL过程管理系统环境及结构

5.2 ETL活动数据流实例入库

笔者根据某地区电信部门的集团上传任务中的“增值业务月数据分析”来设计文档和相关的源表、维表数据。按照上述模型建立元数据库,并录入相关“增值业务月数据分析”元数据,为每种元数据都赋予对应的业务描述。本文认为录入ETL元数据的执行者应该为ETL的设计人员。执行的步骤如下:

建立起模型对应的元数据库,一共8张表。分别是查询集表Query_ColSet、TA活动表Trans_Activity、TS步骤表Trans_Step、CM映射表Classifier_Map、FM映射表Feature_Map、CFM映射表Classifier_Feature_Map、TE执行记录表Trans_Execution以及更改预警记录表Modi_Metadata_Alarm_Info。

录入与该ETL整个活动有关的元数据,设置其编号为“TA001”,录入情况如 图6所示:

图6 ETL活动任务元数据录入情况

录入该ETL活动所包含的ETL步骤,按前面的描述该ETL活动共包含4个ETL步骤。录入情况如 图7所示:

图7 ETL活动步骤元数据录入情况

ETL活动的Trans_Step表新增了一个字段,OBJECT_ID。这个字段表示ETL步骤与数据库中的存储过程的对应关系。另外,ETL_S2与ETL_S3是同时进行的,所以它们的优先级是一样的,是该ETL活动中的第二个步骤。

录入每个步骤中表与表之间的具体映射过程描述。该描述存储在Classifier_Map表里。录入情况如 图8所示:

图8 表级映射元数据录入情况

可以看出每个ETL步骤中源表与目标表之间的对应关系。在ETL_S1步骤中,目标表是由三张源表整合得来;在ETL_S2和ETL_S3中,它们的目标表是相同的,并且从TM_ID字段中可以看出它们有一个源表F_2_JTSC_SERV_M的变换也是相同的,即TM04。

对于每个TM(Transformation Map)变换来说,它是字段级的多个映射关系的集合,这种映射关系可以是单字段与单字段间的FM(Feature Map)映射,也可以是单字段与多字段间的CFM(Classifier Feature Map)映射。同时,模型在这里得到扩展,增加维表映射关系。表中增加了D_QCS_ID\D_FEATURE_SOURCE与D_FEATURE_TARGET三个字段,分别表示维表的查询记录集编号、维表的源映射字段和目标映射字段。其中,查询记录集代表这样一类数据集合,它们没有被命名,属于表数据的一部分。查询记录集通过对表加入一定限制条件得到。以TM02变换为例,它在FM表、CFM表中的变化如 图9图10所示:

图9 字段级映射元数据录入情况

图10 列集-字段映射元数据录入情况

可以看到,以上包含维表信息的元数据描述是白盒映射。比起只描述源字段和目标字段的黑盒映射来说,它能够更清楚地表示出字段的转换关系,从而为数据溯源分析提供可靠保障。

此外,查询记录集的录入情况如 图11所示:

图11 列集元数据录入情况

在查询记录集里面,包含有记录集来源表、限制条件和条件描述等信息。在限制条件里面,select开头的可以看作是列限制条件,where开头的可以看作是行限制条件。这个限制条件字段可以改进成更加细化的描述,比如细化为两个字段,一个字段记录行限制条件,另一个字段记录列限制条件。但在该ETL案例中,因不涉及到行限制,因此没必要作此改进。该ETL活动中使用到查询记录集的情况有两种:作为FCM映射中的多列端;维表中映射所需的字段列。

记录ETL活动实例执行操作的TE(Trans_Execution)表的数据录入情况与其他ETL元数据的录入情况有所不同。由于它是记录ETL程序执行情况的,所以它的触发事件就是ETL程序的执行。因此,可在每个ETL程序中的开头添加向TE表插入实例记录的操作,在每个ETL程序末尾添加更新TE表对应实例记录的操作,以确保每次执行的情况都能全面地记录下来。

5.3 运行结果

以展示ETL数据流向图为例,该部分功能的意义重在以全面清晰的方式向用户展示有关数据的ETL活动的所有元数据。最终用户在浏览分析数据时,系统用图形化的方式向用户展示分析数据的来源和流向。来源表和中间表以节点来表示,ETL每个步骤以有向箭头表示。如果用户想看到转换的具体过程,可以点击相关步骤,从而得到该步骤中字段级的映射关系。

当最终用户查看主题分析数据时,系统将绘制出该主题分析数据的来源与每步转换的描述。查询情况及图形展示界面如 图12所示:

图12 最终分析数据的数据流向图绘制

6 结语

ETL过程是关系型数据进行整合、变换和聚集的过程,而基于CWM标准的ETL元数据模型很好地描述了这个过程的进行,为其建立了一个变换细节可追溯的流程框架,从而在一定程序上能够预防和解决因人员业务交流、管理体制以及数据处理机制上的不足诱发的数据质量问题。这个元数据库模型不仅可应用在数据仓库领域,在众多IT系统领域的数据变换过程中同样可以得到充分的应用。而元数据对数据变换的业务逻辑和转换方式的描述功能方面上还有很多可利用的地方也值得研究。

由于CWM元数据模型标准是一个比较宏观的建模策略,因此该模型每个类中的属性会因具体应用环境的不同而不同,因此在设计实际的系统时需要按照具体的情况来增删具体的属性。

The authors have declared that no competing interests exist.

作者已声明无竞争性利益关系。

参考文献
[1]曹志伟.  支持ETL进化的元数据管理与应用[D]. 北京: 对外经济贸易大学, 2006. [本文引用:1]
[2]胡细平.  全过程元数据驱动的实时BI基础平台研究[J]. 图书馆学研究, 2010(22): 10-16. [本文引用:1]
[3]赵晓非.  ETL工具的元数据集成与管理研究[J]. 武汉理工大学学报, 2010, 32(16): 115-118. [本文引用:1]
[4]高晓东, 汪恒杰, 胡大斌.  基于CWM的多数据源协同平台设计与实现[J]. 控制工程, 2006, 13(5): 485-487. [本文引用:1]
[5]郑洪源, 周良.  基于CWM的标准ETL的设计与实现[J]. 吉林大学学报: 信息科学版, 2006, 24(1): 50-54. [本文引用:1]
[6]雷启明.  基于CWM的商场数据仓库ETL系统架构研究[J]. 商场现代化, 2008(26): 39-40. [本文引用:1]
[7]程跟上, 郑洪源, 丁秋林.  一种标准的ETL的设计思想及其实现[J]. 计算机应用研究, 2005, 22(3): 101-103. [本文引用:1]
[8]Poole J, Chang D, Tollert D, et al.  Common Warehouse Metamodel Developer’s Guide[M].  New York: John Wiley & Sons Inc, 2003: 69-72. [本文引用:1]
[9]OMG(Object Management Group).  Common Warehouse Metamodel (CWM) Specification. Version 1. 1[S].  Object Management Group, Inc. , Needham, MA, March2003. [本文引用:1]
[10]程跟上.  基于公共仓库模型的ETL系统研究与实现[D]. 南京: 南京航空航天大学, 2005: 18-19. [本文引用:1]
[11]Mazón J N, Trujillo J.  An MDA Approach for the Development of Data Warehuses[J].  Decision Support Systems, 2008, 45(1): 41-58. [本文引用:1] [JCR: 2.201]
[12]刘丽娟.  基于CWM的ETL元数据管理系统研究与实现[D]. 西安: 西北大学, 2008. [本文引用:1]

ETL之metadata (讲了pentato 的kettle 的元数据) - sunnywang - IT博客

$
0
0

--  商业智能平台研究:ETL之metadata

元数据的定义就是:描述数据的数据,你非要问什么描述元数据,还是元数据本身,UML中也有这种概念,只不过是描述的对象不一样罢了。

 

    让我们解释的更加通俗易懂一些吧,在javaSE中也有metadata的概念,最早的就算是JavaDoc了,在5.0之后,Annotation就是大量的使用metadata了,这是关于源代码的数据,具体来说就是关于Java的类、方法、字段等关联的附加数据。这些数据可以被Java的编译器或者其它工具(比如Java IDE 象eclipse+junit一样)来发现和使用。junit在4.0后也使用了Annotation也算是metadata的一种应用。可见metadata并不是什么高不可攀的技术,我们时刻都在使用。

 

    再来看看metadata在BI系统上的定义吧,元数据(Metadata)是关于数据、操纵数据的进程,以及应用程序的结构、意义的描述信息,其主要目标是提供数据资源的全面指南。元数据是描述数据仓库内数据结构和建立方法的数据,可将其按用途分为两类:技术元数据(Technical Metadata)、业务元数据(Business Metadata)和内联映射元数据(Inter-Mapping Metadata)。

    

    技术元数据是存储关于数据仓库系统技术细节的数据,是用于开发和管理数据仓库的数据,主要包括数据仓库结构的描述(各个主题的定义,星型模式或雪花型模式的描述定义等)、ODS层(操作数据存储ODS .Operation Data Storage)的企业数据模型描述(以描述关系表及其关联关系为形式)、对数据稽核规则的定义、数据集市定义描述与装载描述(包括Cube的维度、层次、度量以及相应事实表、概要表的抽取规则)。另外,安全认证数据也作为元数据的一个重要部分进行管理。

业务元数据从业务角度描述了数据仓库中的数据,它提供了介于使用者和实际系统之间的语义层,使得不懂计算机技术的业务人员也能够理解数据仓库中的数据。业务元数据包括以下信息:使用者的业务术语所表达的数据模型、对象名和属性名;访问数据的原则和数据来源;系统所提供的分析方法及公式、报表信息。

 

    内联映射元数据(Inter-Mapping Metadata)实现技术元数据与业务元数据的层间映射,使得信息系统的概念模型与物理模型相互独立,使企业的概念、业务模型重组,以及物理模型的变化相互透明。

 

    内联映射元数据从技术上为业务需求驱动、企业数据驱动的双驱动建设模型提供了重要保证,使信息系统的建设具有更高的灵活性与适应性。

 

    元数据是跟特定的数据对象有关的,换句话说,talend和kettle的元数据就是不一样的。ETL的元数据就和pentaho report 的元数据不一样,因为他们要描述的东西不一样。这些元数据的存储格式可以有多种,可以储存成XML格式的也可以是放在数据库里面的。事实上这两种最通用的,也是可以互补的两种,没有谁比谁重要之说。

 

    metadata储存在repository的地方,我不知道是不是所有的ETL工具都喜欢这么叫.每个repository都会选用数据库来储存,他们都是按照一定的格式,这些格式最后也是可以变成XML形式的.这是看每个工具的支持程度,kettle 就支持导出到XML格式,其他的工具我就不知道了.

 

    具体解释到kettle来说,metadata就是你定义的每一个动作.kettle的repository里面有如下一些表,我没有列出全部,从表的结构看一下kettle的metadata有哪些

1. R_DATABASE R_DATABASE_ATIRIBUTE R_DATABASE_CONTYPE R_DATABASE_TYPE

2. R_JOB R_JOB_HOP R_JOBENTRY R_JOBENTRY_ATIRIBUTE R_JOBENTRY_TYPE

3. R_LOG R_LOGLEVEL

4. R_STEP R_STEP_DATABASE

5. R_TRANS_ATIRIBUTE R_TRANS_HOP R_TRANS_CONDITION

6. R_USER R_VALUE R_PERMISSION

7. R_CLUSTER R_CLUSTER_SLAVE R_SLAVE

8. R_PARTITION R_PARTITION_SCHEMA

 

1 . database的链接信息.在R_DATABASE_TYPE 表里面包含了所有支持的数据库链接信息,一共是25种,算是支持非常的多了.

 

2. 任务设计部分的表,R_JOB_HOP 是指两个数据之间的链接部分, R_JOBENTRY_TYPE 是目前支持的操作种类,一共有27种,包括Transformation , Job , Shell , Mail , SQL ,FTP ,Table exists ,File Exists , JavaScript , Secure FTP , HTTP , Create File , Delete File , Wait for File , Put a file with SFTP , File Compare , BulkLoad into Mysql , Display Msgbox Info , Wait for , Zip file , XSL Transformatio, BulkLoad from Mysql into File , Abort Job , Get mails from POP , Ping a host , Dummy Job Entry .

其中BulkLoad 只跟Mysql有关,我感觉很奇怪,BulkLoad 是数据库批量处理的方式,大型数据库都是支持的,比如oracle就有sqlloader来支持批量处理,其他的大型数据库应该也有吧,而且在transform里面kettle也有oracle的支持,在任务设计的时候就只有mysql的支持,不知道什么原因.

最后一个Dummy Job Entry 就是什么都不做.

 

3. Log记录,loglevel 一共有6种,Nothing at all , Minimal loggin , Basic loggin , Detailed loggin , Debugging , RowLevel(very detailed).根据你自己的需要来选择log的级别.

 

4. 每一步操作的表格与你使用的数据库

 

5. 转换的定义.一共有70种不同的转化,你不会想看到全部列出来的,其中有几种很有用的,比如DimensionLookup , 它的解释就是"在一个数据仓库里更新一个渐变维,或者在这个维里查询信息.

还有基于关键字删除记录,

cuebOutput, 把数据写入一个cube,

从一个excel文件读数据,执行一个sql脚本,调用数据库的储存过程,

OraBulkLoader ,调用oracle 的bulk loader to load data ,(应该是指Oracle的SQLLOADER吧).

ProSAPCONN, 从一个SAP系统取数据.

MergeRows,合并两个数据流, 并根据某个关键字排序. 这两个数据流被比较,以标识相等的、变更的、删除的和新建的记录.

 

    插一句关于merge的概念,从网上copy下来的:

MERGE语句是Oracle9i新增的语法,用来合并UPDATE和INSERT语句。通过MERGE语句,根据一张表或子查询的连接条件对另外一张表进行查询,连接条件匹配上的进行UPDATE,无法匹配的执行INSERT。这个语法仅需要一次全表扫描就完成了全部工作,执行效率要高于INSERT+UPDATE。

 

6. 用户与权限.一开始建立的用户有两种,admin和guest ,权限有5种,Read only access , Administrator , Use transformations , Use Jobs , Use schemas .

 

7. pentaho官方网站上面有一个新闻是关于在mysql的Kettle集群新记录:

    最近Kettle集群基于 Amazon Elastic Computing Cloud做了一次测试,单台服务器输出4000 rows/sec ,数据库为MySQL. 如果你发送数据通过sockets从一个master到5个slave servers, 你将获得 5x4000 row inserts/sec。集群的效果非常好.

 

    我个人也做过测试。数据库是oracle 10.2.0.1,内网连接,从一台机器的oracle到本地机器,没有集群,速度也大概是4000 多一点 ,数据量大概是16万。

 

8 . 数据库分区是数据库的高级特性之一,oracle的XE版和Enterprise版本的有一个差别就是XE版不支持分区。

 

    kettle还支持metadata搜索,可搜索的选项包括步骤,数据库连接和注释 ,可见metadata对于ETL的重要性就是它能够更好的管理你的数据,而不只是让你的数据呆在数据库里面。kettle对与数据库的元数据管理并不是很好,所谓数据库的元数据就比如数据库中表的名字,每一个column的信息,column的长度,每一个表的constrain,index等,而只有提供这些信息的管理才能够将ETL过程做的更好。下一篇介绍ETL质量控制的时候会看到oracle warehouse builder 对于这些数据管理是多么的强大,目前kettle的能力还不能算是非常的强大的。

 

    pentaho平台本身还有一种metadata , 在官方主页上是这么写的:

 

    pentaho metadata的能力是让管理员定义一个抽象层来显示数据库信息和商业流程,管理员用关系型数据库的表来表现相互之间的关系,为了复杂和含义模糊的数据库表和列而创建商用术语,为特性用户而设定权限参数,指定默认的数据格式,为多种语言部署提供翻译,商业用户可以使用pentaho新的ad hoc query能力查询他们想要的报表,比如订单的数量和按地区排序的客户开销,SQL可以自动取得这些信息。

 

    数据仓库的建模也需要用到metadata, oracle的数据仓库建模就是用的一种叫 Common Warehouse Metamodel 的metadata , CWM提供一个数据仓库的标准让不同的厂商集成和管理他们的数据,CWM建立在开发的标准XMI(XML for Metadata interchange) XML 和 UML2 作为建模语言。CWM 用UML2 定义一组核心类,这些类分作package(或者叫做子模型submodels),每一个提供一个特定的数据仓库的domain , 比如 Relational , OLAP ,Transformation , CWM 提供一个强大的数据模型来实现数据仓库的Extraction , transformation , loading , integration and analysis ,没有一个单独的模型能够满足各种应用程序和开发工具的需求,但是CWM 为这些工具提供特定的扩展,它被设计用来支持关于metadata的快速开发,使用户能够通过扩展来满足他们的需求。


美团:掉进数据治理无止境的坑,我是怎么爬出来的?

$
0
0

 

一、背景介绍

 

数据治理这个话题这两年非常火热,很多公司尤其大型互联网公司都在做一些数据治理的规划和动作。为什么大家都要做数据治理?我个人的理解是,从数据产生、采集、生产、存储、应用到销毁的全过程中,可能在各环节中引入各种问题。初始发展阶段,这些数据问题对我们的影响不大,大家对问题的容忍度比较高。但是,随着业务发展数据质量和稳定性要求提升,并且数据积累得越来越多,我们对一些数据的精细化要求也越来越高,就会逐渐发现有很多问题需要治理。数据开发过程中会不断引入一些问题,而数据治理就是要不断消除引入的问题,以高质量、高可用、高安全的方式为业务提供数据。

 

 

1、需要治理哪些问题 

 

数据治理过程中哪些问题需要治理?总结了有五大类问题。

 

 

  • 质量问题,是最重要的问题,很多公司数据部门或者业务线组做数据治理的一个大背景就是数据质量存在很多问题,比如数仓的及时性、准确性、一致性、规范性和数据应用指标的逻辑一致性问题;

     

     

     

  • 成本问题,互联网行业数据膨胀速度非常快,大型互联网公司在大数据基础设施上的成本投入占比非常高,而且随着数据量的增加成本也将继续攀升;

     

     

     

  • 安全问题,尤其是业务特别关注的用户类数据,一旦泄露,对业务的影响非常大,甚至能影响整个业务的生死;

     

     

     

  • 标准化问题,当公司业务部门比较多的时候,各业务部门、开发团队的数据标准不一致,在数据打通和整合过程中会出现很多问题;

     

     

     

  • 效率问题,在数据开发和数据管理过程中都会遇到一些效率低的问题,很多时候是靠堆人力在做。

     

     

 

2、美团酒旅数据现状 

 

美团酒旅业务从2014年成立为独立业务部门,到2018年成为国内酒旅业务重要的在线预订平台,业务发展速度比较快,数据增长速度也非常快。2017到2018两年里,生产任务数以每年超过一倍的速度增长,数据量的增长速度每年两倍多。如果不做治理,按指数级增长趋势,未来数据生产任务的复杂性还是成本负担都非常大。

 

针对我们当时面临的情况,总结了五大类问题:

 

  • 标准化的规范缺失,开始建设的时候业务发展非常快,但多个业务线之间的标准化和规范化建设都只是以规范文档的形式存在,每个人的理解不一致,导致多个研发同学开发出来的数据标准就很难达到一致;

     

  • 数据质量问题比较多,突出在几个方面,第一个是数据冗余很多,从数据任务增长的速度来看,新上线人多,下线任务少,数据表的生命周期控制较少。第二个是在数据建设过程中很多应用层数据都是烟囱式建设,很多指标口径没有统一的管理规范,数据一致性无法保证;

     

  • 成本增长非常快,在某些业务线大数据存储和计算资源的机器费用占比已经超过了35%,如果不加以控制,大数据成本费用只会越来越高;

     

  • 数据安全的控制,各业务线之间可以共用的数据比较多,而且每个业务线没有统一的数据权限管理;

     

  • 数据管理和运维效率低,数据使用和咨询多,数据RD需要花费大量时间解答业务用户的问题。

     

 

二、治理实践

 

2018年以前酒旅数据组也做过数据治理,从数仓建模、指标管理和应用上做优化和流程规范,当时没有做体系化的数据治理规划。从2018年以后我们基于上面提到的五个问题,我们做了一个整体的数据治理策略。

 

我们把数据治理的内容划分为几大部分:组织、标准规范、技术、衡量指标。整体数据治理的实现路径是以标准化的规范和组织保障为前提,通过做技术体系整体保证数据治理策略的实现。同时会做数据治理的衡量体系,随时观测和监控数据治理的效果,保障数据治理长期向好发展。

 

 

1、标准化和组织保障 

 

每个公司在做数据治理时都会提到标准化,我们总体思路也没有太大区别。数据标准化包括三个方面:第一是标准制定,第二是标准执行,第三是在标准制定和执行过程中的组织保障,比如怎么让标准能在数据技术部门、业务部门和相关商业分析部门统一。

 

 

从标准制定上,我们制定了一个全链路的数据标准方法,从数据采集、数仓开发、指标管理到数据生命周期管理建立了很多标准,在标准化建立过程中联合组建了一个业务部门的数据管理委员会。管理委员会是一个虚拟的组织,主要组成是技术部门和业务部门,技术部门是业务数据的开发团队,业务部门是业务数据的产品团队,这两个团队作为实现的负责人,各自对接技术团队和业务团队,比如技术团队负责协调后台开发团队、大数据平台团队、数据分析系统团队等。业务则会协调商业分析、产品运营和一些业务部门。业务各个部门分别出人把数据管理委员会运行起来,为标准制定、执行提供组织保障。让大家对标准化制定能有更加统一的认知,执行过程阻力也更小,还能定期在组织内同步信息。

 

2、技术体系 

 

在执行过程中也不希望完全通过人力和组织来推动达成,总体希望以一些自动化的方式进行。下面介绍一下我们的技术体系。

 

1)数据质量

 

数据质量是数据质量中最重要的一个问题,现在数据治理的大部分问题都属于数据质量。这里有四大问题:

 

  • 数据仓库的综合性比较差,虽然有一些规范文档,但更依赖个人理解去执行;

  • 数据一致性问题多,主要表现在数据指标的管理上。指标管理以前在文档中定义指标,没有系统化的统一管理逻辑和查询逻辑;

  • 数据应用非常多,使用数据的方式包括数据表同步、接口消息推送、OLAP引擎查询等,不能保证数据应用端的数据一致性;

  • 产品非常多,业务数据产品入口有十多个,没有统一的入口,也没有人对这些产品统一把关,导致数据应用和使用方式有很多分歧。

 

我们的技术实现方式是为了解决上面这四大类质量问题,首先在数据仓库规范性上进行统一,然后统一指标逻辑,在此之上统一数据服务接口,最后在产品上统一用户产品入口。从这四大方向将常见的数据质量问题管控起来,具体技术实现方式如下。

 

 

①数仓建模规范

 

统一数仓建模规范分三大部分实现,以前我们只有事前的一些标准化规范,大家按自己的理解去建模实现。在这个基础上增加了事中和事后两个部分,针对事中开发了系统化工具,做数仓配置化开发。事后做规则化验证。事前会有标准化文档给大家提前理解、宣贯,事中很多标准化的事项会通过配置化自动约束规范,事后会有上线时的检验和上线后每周定期检验,检验数据仓库的建模规范是否符合标准,把不符合标准的及时提示出来、及时改进。

 

 

事前的标准化规范几个方向,第一是数据仓库的设计规范,在做一个新业务或模块之前,以文档形式做一些设计规范。第二是开发规范,包括一些开发流程、代码编写规范和注释信息。

 

这些形成之后还想在事中以系统化的方式进行控制,保证不会因为每个人的不同理解而对数仓的规范化构成影响。这里主要包含三部分工具:

 

  • 模型开发过程中的开发工具,主要控制模型的基础信息、数仓主题和分层以及ETL代码生成;

  • 命名规范工具,针对模型、表、字段、指标建了很多一些规范化的系统实现,控制这些命名的标准化;

  • 上线规则监控工具,上线过程中会监控一些数据规范,还有一些性能监控,有问题会及时发现。

 

事后会定期监控,生成报告来看每个业务线、每个组、具体每个人的数仓规范性情况。

 

对于具体的实现方案,我举一个简单的例子,一个数仓开发配置化的命名规范工具。我们工具的实质还是从规范化、标准化再到工具化,所以在前期做了一些规范化、标准化,在通过工具化把标准化和规范化通过系统实现,有了工具之后,比如人在数仓时,都会统一按相同的方式来命名,即便在几千个ETL里都有这个字段也能非常快地进行定位。命名工具和数仓建模ETL工具也进行了打通,命名审核通过后,直接点击就能在ETL工具的平台中生成一段代码,只需要将查询逻辑补充进去就可以了。这样就达到了控制数仓命名规范的目的。

 

 

②统一指标管理系统

 

指标在数仓中非常重要,所有数据应用都是以指标方式使用的。指标管理系统化主要做了流程管理标准化、指标定义标准化和指标使用标准化。系统化分三层,第一层是物理表管理,第二层是模型管理,第三层是指标管理,这些信息在元数据管理中统一进行。

 

 

统一规范只是指标管理的第一步,除了指标管理外,所有数据应用还能通过这个工具查询数据。具体做法,一个应用无非要查询两种数据,一是维度,二是指标。在查询指标时,可能会有一些维度限制条件。在指标管理模块中通过指定指标定位到数仓模型,了解指标的获取方式(是sum还是count等)。相应的数仓模型可是能是星型模型、宽表、循环模型,从模型中解析出对应的底层物理表。解析后,结合指标、维度和筛选条件,经过不同的存储引擎,解析成不同的查询语句。这样控制好数据指标管理之后,数据应用可以通过指标管理模块获得一致性的解析。

 

 

③统一数据服务

 

我们的数据被很多下游系统使用,比如数据产品、业务系统、运营系统、管理系统等。有些下游既需要我们提供数据表,还要提供接口,但数据组开发和维护后台接口难度较大,而且接口提供后很难把控数据的用途。所以我们做了一个统一的数据服务平台。平台目标是提高效率、提高数据准确性、提供数据监控、将整个数据仓库和数据应用链路打通。提供的方式有两种,一种是对于B端应用,提供按需使用,每天提供几万次的调用额度;一种是对于C端,通过推送的方式,比如每天推送一次最新数据。以推和拉两种方式保证服务功能的全面性,具体实现,大家可以参考下图:

 

 

分为几大层次:

 

  • 导入层;

  • 存储层,数据根据不同的使用场景会有很多种不同的存储方式,比如根据条件查询一条数据的情况KV最合适,一些对定性条件要求很高的简单汇总用MySQL,一些数据量非常大但频率低的用OLAP引擎;

  • 服务层,对存储引擎查询进行一些封装;

  • 控制层,进行权限管理、参数校验和业务资源隔离;

  • 接口层,提供不同的查询方式,如聚合查询、KV查询、详情查询和分组查询。

 

④统一用户产品入口

 

因为数据入口非常多,我们又做了一个数据入口的统一,分成三大类:

 

  • 管理者和商业分析使用的分析决策产品;

  • 业务销售运营用的业务销售数据产品;

  • 数据资产管理产品。

 

通过这种方式,某一类用户只需要在一类入口里访问一类产品,不会出现同一类产品中的数据不一致。我们又通过数据仓库的统一建模、数据指标管理保证了三大类底层数据集市的一致,从而保证了所有数据的一致性。

 

 

⑤整体系统架构

 

整体的技术架构分为三层,从统一数据建模到统一指标逻辑、统一数据服务和统一产品入口,整体保障了数据的质量,同时配合数据管理的组织保障体系和流程规范,将整体数据质量相关的架构搭建起来。

 

 

2) 数据运营效率

 

作为数据提供方,我们有很多数据资产,但数据使用方能不能快速找到、找到怎么用、有哪些数据,有三大类问题:

 

  • 找不到,不知道数据有没有、在哪里;

  • 看不懂,有很多业务方不是技术研发团队的,看不懂数据到底什么含义、怎么关联查询、来源于哪个业务系统;

  • 不会用,如何写SQL或者哪些产品里面能查询到自己想要的数据指标。

 

基于此有三大目标:找得到、看得懂、用得对。为了提效,我们选用一些智能化系统代替人工。对于运营相关的数据问题,先提供系统化的数据指南。该指南包含三大类信息:指标类、数仓模型、推荐使用方式。这个方式能解决可能60%的问题,剩下的40%再通过答疑机器人,用一些机器的方式替人回答问题,这又能解决其中60%的问题。最后还有一些还是没找到的,落到人工答疑环节就非常少了,通过自动化把需要人工做的事情降到原来的20%以下。

 

 

具体的实现方式,针对数据使用指南做了一个系统,把指标元数据、维度元数据、数据表和各种产品元数据等管理起来。用户从入口查询能够快速定位,支持分类检索和重点词检索,还会提供排序进行重点推荐,对每一个主题数据分类描述。通过数据指南能解决很多问题,不能解决的就进入答疑机器人系统,这里主要解决一些元数据里没有的问题。我们日常通讯工具上会有问答,把这些问题和答案总结成一个知识库,进行清洗和规则匹配。对这类问答的解析成一个问题对应一个答案,通过一些规则和关键字匹配后存起来。之后再查的时候只输入一个问题时,根据这个解析出来他想问的可能有几个问题,将这几个答案抛给他。

 

 

3) 数据成本

 

美团业务的数据成本也很大,每一年的数据存储、计算相关的成本增长非常快。美团目前大概的比例是70%的计算成本、20%是存储成本、10%为采集日志。针对这三大类,我们也分别做了一些数据成本治理的方案。

 

 

针对计算类,主要做了如下事情:

 

  • 无效任务治理;

  • 超长任务优化;

  • 提高资源满用率;

  • 资源统一管理。

 

针对存储类:

 

  • 冷数据治理;

  • 重复数据治理;

  • 数据生命周期管理;

  • 存储格式压缩;

 

日志采集类:

 

  • 日志下游应用监控;

  • 日志上报方式优化;

  • 无效埋点优化。

 

整体的方案策略方面做了精细化拆分,比如按租户(每个业务线的用户)来看,租户下有队列,队列有离线、有实时。队列下面有计算、存储、采集,计算之中又分离线、实时,有些配置量、使用量。这样可以非常容易地定位到哪些租户、哪些数仓是有问题的,对应快速治理。

 

这方面也做了很多系统化的事情,比如有一个数据冗余判断的逻辑,每次做完数仓建模之后,会做冗余判断。元数据生成之后进行预处理,根据现有的数据做预判,看是否已存在。通过配置的对比逻辑,如果认为数据重复,会做标记并每周推送到数据治理的看板上,及时将冗余数据治理掉。

 

4)数据安全

 

数据安全我们是以事前预防、事中监控、事后追踪三个方式来进行的。实践经验上,通过三层系统控制加五个使用原则实现。从数据产生的源头业务系统里就会将一些非常敏感的用户数据加密,数据仓库层会对各分层的数据进行脱敏和二次加密,第三层专门做一些数据审计,在数据使用全流程中提供信息提示和审计报告。

 

 

数据使用过程中应当遵循的五个原则:

 

  • 密文处置原则,所有高敏感的数据都要密文传输;

  • 最晚解密原则,在应用层产品使用的话,不要在数据仓库层解密;

  • 最小范围提取原则,如果只用一万条数据只能对一万条数据解密;

  • 最小授权原则,用多少给多少;

  • 全程审计原则,从系统流出到使用全过程都是有措施保障。

 

3、衡量指标 

 

未来能够全面的衡量数仓治理的效果,我们新建了数据衡量指标体系,总体分为五大类:质量类、成本类、安全、易用性和价值。在监控方式上分为日常监控和定期监控(周、月、季度监控),让我们知道整体数据治理是整体向好、平稳还是向坏的。

 

 

根据PDCA原则,将数据治理作为日常运营项目做起来,底层依赖数据指标体系进行监控,之上从发现问题到提出优化方案,然后跟进处理,再到日常监控构成一个循环。

 

三、未来规划

 

总体来说,数据治理分为三个大阶段:被动治理、主动治理、自动治理。

 

第一阶段我们做的是被动治理,也就是阶段性治理,没有统筹考虑,主要是基于单个问题的治理,而且治理之后过一段时间可能要做重复治理。这个阶段更多是人治,一个项目成立,协调几个人按照项目制完成,没有体系规划也没有组织保障。

 

第二阶段是主动治理,有长期的统筹规划,能覆盖到数据生命周期的各个链路,在治理过程中把一些手段和经验流程化、标准化、系统化,长期解决一些数据问题,让数据治理长期可控。

 

第三阶段是自动治理,也是智能治理,希望长期规划和数据生命周期个环节链路确定好之后,把已经有的经验、流程和标准做成策略。一旦出现问题,自动监控,通过一些系统化的方式解决。自动治理的第一步还是治理方案的落地和策略化,这就非常依赖于元数据,把数据治理各个过程中的一些经验技术都沉淀起来。做完策略沉淀之后做自动化,把策略用工具的方式实现,当系统发现数据有问题时,自动去处理。

 

现在酒旅的数据治理还在第二阶段和第三阶段之间,虽然有整体治理计划、技术架构和组织保障,但还需要投入很多人力去做。之后,酒旅数据也会继续朝着智能化的方向做,把自动化治理做好。

 

今天的分享就到这里,谢谢大家。

 

Apache Derby Papers

$
0
0

Apache Derby Papers

This  ad hoc spot in the Derby site hosts papers, and check the  Derby Wiki for more.

Derby Engine

The table below summarizes resources that describe the Derby engine.

Navigation Menu EntryTitle
JavadocEngine
Language
Tools
API
ArchitectureDerby Engine Architecture Overview
BTreeBTree package documentation
Disk Page FormatDerby On Disk Page Format
How Things WorkHow Things Work
Intersect & ExceptIntersect & Except Design
JDBCDerby JDBC Implementation Notes
Log FormatDerby Write Ahead Log Format
Logging & RecoveryDerby Logging and Recovery
OptimizerDerby Optimizer Design
Type SystemDerby Type System (Note: if your browser shows HTML source for this page instead of displaying it, save the file locally with  File -> Save Page As, then open the file you saved.)
VersioningDerby Versioning Scheme

Derby Network Client

The table below summarizes white papers that describe the Derby Network Client.

Navigation Menu EntryTitle
Functional SpecDerby Network Client

Instruction

The online  Apache Derby Tutorial provides a quick hands-on overview. Pointers to even more tutorials and other instructional materials are on the  Derby Wiki.

How to Contribute Papers

If you have figured out how something works in Derby or how to do something cool and have produced a white paper you would like to contribute to the Derby web site, please  open a Jira issue with the component set to "Web Site". Upload your contribution to that issue with the "Attach file to this issue" option. It will prompt you to click on "Grant license to ASF for inclusion in ASF works", and this is the permission we need in place to host your contribution on the Derby web site.

As time permits, somebody will take the document from the Jira issue and put it on the Derby web site. You can speed the posting process up by  testing your white paper in Forrest to verify it works well before you post it.

If you want the paper integrated with the Derby web site, with the forrest-generated navigation, it is easiest to incorporate these types of files:

That much said, even though your favorite word processing program can produce an HTML file, that doesn't necessarily mean that forrest can read it and do something visually pleasing with it. If forrest can't consume your document, or you don't like what forrest did with it, or you want to provide your document in a binary format it can be included in its native format on the site -- it just won't have the forrest-generated left hand navigation and top banner. Examples are:

You can also link directly to a file in the Derby code tree; for example, to the  Building Derby file. Don't link with a viewcvs URL like the one below because it turns out to put a heavier burden on the server than is needed:

   https://svn.apache.org/viewcvs.cgi/*checkout*/db/derby/code/trunk/BUILDING.txt

ViewCVS is good for when you need to browse the history. But if all you need to do is display the file, link to it like this instead:

   http://svn.apache.org/repos/asf/db/derby/code/trunk/BUILDING.txt

Last Updated: March 30, 2005

通过SQL定义用户浏览Session

$
0
0

PC时代,用户问页面时,我们会先检查用户的Cookie中是否存在SessionId,如果不存在,则会通过随机数的方式生成一个SessionId存入Cookie中。如果存在,我们会更新这个Cookie的失效时间(30分钟后)。即只要用户访问的间隔在30分钟内则被认为是同一个Seesion,超过30分钟则会生成一个新的SeesionId,将浏览定义为一个新的Session。

APP时代或者小程序的时代,通常我们会把App的每次打开作为一次Seesion来记录,Cookie的概念被抛弃,但中间忽略了一个重要的问题:在你使用App或者小程序的过程,非常有可能会被其他应用程序中断,比如电话、短信、微信、推送等。当用户切屏以后Session的记录就会发生改变,这时候统计的Session数据往往是不准确的。今天要分享的是如何通过SQL的方式来定义Session。

理清思路

用户浏览日志中,我们通常能够记录到用户的身份和访问时间。在Session定义中我们首先需要识别唯一用户,并按用户的浏览时间对日志进行排序,处理完成后需要计算日志间的时间差,并将大于30分钟的浏览定位为新的Session。

逻辑转SQL

1 计算每次访问的上次访问时间

可以使用窗口函数LAG实现。具体代码如下:

SELECT *, LAG(occurred_at, 1) OVER (PARTITION BY user_id ORDER BY occurred_at) AS last_event
FROM tutorial.playbook_events

执行效果如下:

其中:

  • user_id:用户身份ID
  • occurred_at:当前访问时间
  • last_event:上次访问时间

2 计算访问时间差,确定是否为新的访问

判断是否是新的访问主要通过两种方式:

  • 本次访问没有上次访问时间
  • 本次访问和上次访问时间差>30分钟(30分钟还是10分钟可以根据业务场景自己定义)
SELECT *
    , CASE 
        WHEN unix_timestamp(occurred_at, 'yyyy-MM-dd HH:mm:ss') - unix_timestamp(last_event, 'yyyy-MM-dd HH:mm:ss') >= 60 * 30
        OR last_event IS NULL THEN 1
        ELSE 0
    END AS is_new_session
FROM (
    SELECT *, LAG(occurred_at, 1) OVER (PARTITION BY user_id ORDER BY occurred_at) AS last_event
    FROM tutorial.playbook_events
) t1

执行效果如下:

2 定义SessionId

有了上面的数据,还缺一个SessionId,实现的方法还是通过窗口函数实现。具体代码如下:

SELECT user_id, occurred_at, SUM(is_new_session) OVER (ORDER BY user_id, occurred_at) AS global_session_id
    , SUM(is_new_session) OVER (PARTITION BY user_id ORDER BY occurred_at) AS user_session_id
FROM (
    SELECT *
        , CASE 
            WHEN unix_timestamp(occurred_at, 'yyyy-MM-dd HH:mm:ss') - unix_timestamp(last_event, 'yyyy-MM-dd HH:mm:ss') >= 60 * 30
            OR last_event IS NULL THEN 1
            ELSE 0
        END AS is_new_session
    FROM (
        SELECT *, LAG(occurred_at, 1) OVER (PARTITION BY user_id ORDER BY occurred_at) AS last_event
        FROM tutorial.playbook_events
    ) t1
) t2

执行效果如下:

参考链接:

写给前端的跨平台方案、跨端引擎的本质

$
0
0

近些年来,前端领域的跨端技术越来越多了:react native、weex、flutter、electron、kraken 等等。

那么多跨端方案,他们有没有通用的思路?我们能不能从这么多方案中找出本质的原理?

本文会尝试探究探究以下问题:

  • 什么是跨平台
  • 有哪些方案是跨平台的
  • 跨端和跨平台的区别是什么
  • 前端领域有哪些跨端方案
  • 跨平台、跨端的通用原理是什么

什么是跨平台

我们知道,cpu 有不同的架构和指令集,上层也有不同的操作系统,一个系统的可执行文件在另一个系统上就是不可执行的,比如 windows 的 exe 文件在 mac 上就不能直接执行。不同的系统就是不同的运行平台。可执行文件是不跨平台的。

不同平台提供的 api 不同,所以代码逻辑可能也不同,需要不同平台单独维护代码。这样就带来了几个问题:

  • 多平台各自开发,怎么保证功能是一致的
  • 多平台各自开发,那是不是得各自测试,开发和测试的人力都是多份的

所以出现了跨平台的一些技术,目标是一份代码跑在任意平台。

我们先来看一些各领域的跨平台方案:

浏览器

操作系统不同,浏览器上跑的网页的代码确实同一份。浏览器就是一种历史悠久的跨平台方案。

网页跨平台不意味着浏览器也是跨平台的,浏览器的可执行文件还是每个平台单独开发和编译的,但是他们支持的网页解析逻辑一样,这样上面跑的网页就是跨平台的。

浏览器提供了一个容器,屏蔽了底层差异,提供了统一的 api(dom api),这样就可以实现同一份代码跑在不同平台的统一的容器里。这个容器叫做浏览器引擎,由 js 引擎、渲染引擎等构成。

docker

docker 是一种虚拟化技术,可以在操作系统之上加一个虚拟层,在这层之上划分一到多个容器,容器里再去跑系统、app,这样可以实现硬件和软件的分离,动态分配硬件资源给容器,并且方便 app 运行环境的整体迁移(保存成镜像)。

docker 很明显也是一种跨平台技术,同一个镜像可以跑在任何操作系统的 docker 上。只要不同操作系统实现同样的容器即可。

jvm

java 是一门编译 + 解释的语言,java 源码编译成字节码,然后字节码直接在 vm 上解释执行。

java 为什么这么火呢?主要是因为跨平台。

c、c++ 这种语言写的代码需要编译成不同操作系统上的可执行文件来跑,而且每个平台的代码可能还不一样,需要写多份。

java 因为提供了 jvm 容器,只要把源码编译成 jvm 能解释的字节码就行了,而且 jdk 提供了统一的 api,分别由不同操作系统的底层 api 来实现,这样对于 java 代码来说,不同操作系统的代码是一致的。

jvm 也是通过容器的技术实现了一份代码跑在多个平台,而且 jre 提供了统一的 api,屏蔽掉了底层的差异。

node、deno

node 和 deno 也是跨平台的技术,通过提供一套一致的 api,让其上的 js 代码可以跨平台。这些 api 也是不同平台各自实现的。

electron

electron 内置了 chromium,并为其注入了 node 的 api 和一些 GUI 相关的 api,是基于两大跨平台技术综合而成的跨平台方案。基于这些方案的组合使得 electron 支持用前端技术开发桌面端。

跨平台方案的优缺点

跨平台方案的优点很明显,就是一份代码跑在不同平台的同样的容器内,不用不同平台单独开发,节省成本。

但是跨平台方案也有缺点:

  • 因为多了一层容器,所以性能相比直接调用系统 api 会有所下降

  • 为了实现多平台的一致,需要提供一套统一的 api,这套 api 有两个难题:

    • api 怎么设计。要综合不同平台的能力,取一个合适的集合来实现。设计上有一定难度。node、deno、java 都抽象了操作系统的能力,提供了各自的跨平台 api

    • 部分 api 很难做到多平台的一致性

    • 当容器没有提供的能力需要扩展的时候比较麻烦,比如 js 引擎的 bridge、 jvm 的 jni、node 的 c++ addon 等都是为这个容器扩展能力的方式

前端领域的跨端方案

跨平台指的是跨操作系统,而跨端是指客户端。

客户端的特点就是有界面、有逻辑,所以包含逻辑跨端和渲染跨端。主要的客户端有 web、安卓、ios、iot 设备等。

现在主流的跨端方案有 react native、weex、flutter、kraken 以及各家自研的跨端引擎等。

react native

跨端包括逻辑跨端和渲染跨端,rn 的逻辑跨端是基于 js 引擎,通过 bridge 注入一些设备能力的 api,而渲染跨端则是使用安卓、ios 实现 react 的 virtual dom 的渲染。

其中 native api 和组件(灰色画出的部分)并没有做到双端一致,而且有的时候扩展图中灰色部分需要原生配合,混杂 rn 代码和自己扩展的代码导致代码比较难管理。最著名的事件就是 airbnb 从最大的 react native 支持者到弃用 react native。

weex

weex 也是类似的思路来实现跨端的,不过他对接的上层 ui 框架是 vue,而且努力做到了双端的组件 和 api 的一致性(虽然后续维护跟不上了)。架构和上图类似。

flutter

flutter 是近些年流行的跨端方案,跨的端包括安卓、ios、web 等。它最大的特点是渲染不是基于操作系统的组件,而是直接基于绘图库(skia)来绘制的,这样做到了渲染的跨端。逻辑的跨端也不是基于 js 引擎,而是自研的 dart vm 来跨端,通过 dart 语言来写逻辑,

kraken

跨端包括两部分,渲染跨端和逻辑跨端。有时候只需要渲染跨端、有时候只需要逻辑跨端,有的时候需要完整的跨端引擎,这 3 种情况都有各自的适用场景。

kraken 就是一个跨端渲染引擎,基于 flutter 的绘图能力实现了 css 的渲染,实现了渲染的跨端。

自研渲染引擎

跨端引擎很依赖底层实现的组件和 api,用开源方案也一样得扩展这部分,所以有一定规模的团队都会选择自研。

自研跨端引擎会和 rn、weex 不同:

  • 渲染部分不需要实现 virtual dom 的渲染,而是直接对接 dom api,上层应用基于这些 dom api 实现跨端渲染。这样理论上可以对接任意前端框架。

  • 逻辑部分也是基于 js 引擎,通过 binding 直接注入一些 c++ 实现的 api,或者运行时通过 bridge 来注入一些安卓、ios 实现的 api。

自研跨端引擎的好处是组件和 api 可以自己扩展,更快的响应业务的需求。其中组件和 api 的双端一致性,以及统一的 api 的设计都是难点。

跨端的通用原理是什么

其实跨端和跨平台的思路类似,都是实现一个容器,给它提供统一的 api,这套 api 由不同的平台各自实现,保证一致的功能。

具体一些的话,跨端分为渲染和逻辑跨端,有的时候只需要单独的渲染跨端方案(比如 karen)和逻辑跨端方案,有的时候需要完整的跨端引擎。

weex、react native 的渲染部分都是通过实现了 virtual dom 的渲染,用安卓、ios 各自的渲染方式实现,逻辑部分使用 js 引擎,通过 bridge 注入一些安卓、ios 的 api。

flutter 则是直接使用 skia 绘图库绘制,并且逻辑跨端使用 dart vm。

但是不管具体实现怎样,思路都大同小异: 跨端引擎需要实现一个渲染引擎、实现一个 vm,基于这套架构实现各种组件和 api,跨端容器上层对接一个 ui 框架,再上层的业务代码可以基于容器的 api 实现跨端的渲染和逻辑

web container

这两天 web container 比较火,其实也是一种跨平台技术,它是在浏览器里面实现的容器,通过 wasm 实现了 node 的 api,这样在这个容器里面可以跑 node 代码。其实思路比较常见,但是是一个新场景。

浏览器容器之上又跑了个容器,容器套娃。

总结

我们聊了跨平台和跨端的区别,跨平台是指跨操作系统,而跨端则是指跨客户端。

跨平台技术聊了 docker、浏览器、jvm、node、deno、electron、web container 等,他们都是跨平台(操作系统)的方案,跨平台有优点也有缺点,缺点就在于 api 的设计比较难,node、deno、java 等都有自己的一层 api 设计;api 一致性的保障也比较困难;其次就是扩展方式复杂一些(jvm 的 jni、node 的 c++ addon 等)。

跨端方案聊了 react native、weex、flutter、kraken 等,有的是绑定了 react、vue 等前端框架,直接从 virtual dom 渲染,有的是实现了 dom api,可以对接任意前端框架。当然可以单独做渲染或逻辑跨端。渲染跨端或者用安卓、ios 提供的方式,或者自己绘制,逻辑跨端或者用 js 引擎(可以对接前端框架)或者用 dart vm。

希望这篇文章可以让你理解跨端和跨平台的容器的思路和优缺点,遇到一些新技术(比如 web container)也能快速的理解。


从源码中来,到业务中去,React性能优化终极指南

$
0
0

前言:我们从React源码入手,结合有道精品课大前端的具体业务,运用三大原则对系统进行外科手术式的优化。同时介绍React Profiler这款工具如何帮我们定位性能瓶颈前言:我们从React源码入手,结合有道精品课大前端的具体业务,运用三大原则对系统进行外科手术式的优化。同时介绍React Profiler这款工具如何帮我们定位性能瓶颈

作者/ 安增平

编辑/ Ein

React性能优化是在业务迭代过程中不得不考虑的问题,大部分情况是由于项目启动之初,没有充分考虑到项目的复杂度,定位该产品的用户体量及技术场景并不复杂,那么我们在业务前期可能并不需要考虑性能优化。但是随着业务场景的复杂化,性能优化就变得格外重要。

我们从React源码入手,结合有道精品课大前端的具体业务,运用优化技巧对系统进行外科手术式的优化。同时介绍一下React Profiler这款性能优化的利器是如何帮我们定位性能瓶颈的。

本文中的项目代码全部是在有道大前端组开发项目中的工作记录,如有不足欢迎在留言区讨论交流,笔芯❤

页面加载流程

  1. 假设用户首次打开页面(无缓存),这个时候页面是完全空白的;
  2. html 和引用的 css 加载完毕,浏览器进行 首次渲染
  3. react、react-dom、业务代码加载完毕,应用第一次渲染,或者说 首次内容渲染
  4. 应用的代码开始执行,拉取数据、进行动态import、响应事件等等,完毕后页面进入 可交互状态;
  5. 接下来 lazyload 的图片等多媒体内容开始逐渐加载完毕;
  6. 直到页面的其它资源(如错误上报组件、打点上报组件等)加载完毕,整个页面加载完成。

我们主要来针对React进行剖析

React 针对渲染性能优化的三个方向,也适用于其他软件开发领域,这三个方向分别是:

  1. 减少计算的量:React 中就是减少渲染的节点或通过索引减少渲染复杂度;
  2. 利用缓存:React 中就是避免重新渲染(利用 memo 方式来避免组件重新渲染);
  3. 精确重新计算的范围:React 中就是绑定组件和状态关系, 精确判断更新的’时机’和’范围’. 只重新渲染变更的组件(减少渲染范围)。

如何做到这三点呢?我们从React本身的特性入手分析。

React 工作流

React 是声明式 UI 库,负责将 State 转换为页面结构(虚拟 DOM 结构)后,再转换成真实 DOM 结构,交给浏览器渲染。State 发生改变时,React 会先进行Reconciliation,结束后立刻进入Commit阶段,Commit结束后,新 State 对应的页面才被展示出来。

React 的 Reconciliation需要做两件事:

  1. 计算出目标 State 对应的虚拟 DOM 结构。
  2. 寻找「将虚拟 DOM 结构修改为目标虚拟 DOM 结构」的最优方案。

React 按照深度优先遍历虚拟 DOM 树的方式,在一个虚拟 DOM 上完成Render和Diff的计算后,再计算下一个虚拟 DOM。Diff 算法会记录虚拟 DOM 的更新方式(如:Update、Mount、Unmount),为Commit做准备。

React 的 Commit也需要做两件事:

  1. 将Reconciliation结果应用到 DOM 中。
  2. 调用暴露的hooks如:componentDidUpdate、useLayoutEffect 等。

下面我们将针对三个优化方向进行精准分析。

减少计算的量

关于以上 ReconciliationCommit两个阶段的优化办法,我在实现的过程中遵循 减少计算量的方法进行优化( 列表项使用 key 属性)该过程是优化的重点,React 内部的 Fiber 结构和并发模式也是在减少该过程的耗时阻塞。对于 Commit在执行hooks时,开发者应保证hooks中的代码尽量轻量,避免耗时阻塞,同时应避免在 CDM、CDU周期中更新组件。

列表项使用 key 属性

特定框架中,提示也做的十分友好。假如你没有在列表中添加key属性,控制台会为你展示一片大红

系统会时刻提醒你记得加Key哦~~

优化Render 过程

Render 过程:即Reconciliation中计算出目标 State 对应的虚拟 DOM 结构这一阶段 。

触发 React 组件的 Render 过程目前有三种方式:

  1. forceUpdate、
  2. State 更新、
  3. 父组件 Render 触发子组件 Render 过程。

优化技巧

PureComponent、React.memo

在 React 工作流中,如果只有父组件发生状态更新,即使父组件传给子组件的所有 Props 都没有修改,也会引起子组件的 Render 过程。

从 React 的声明式设计理念来看,如果子组件的 Props 和 State 都没有改变,那么其生成的 DOM 结构和副作用也不应该发生改变。当子组件符合声明式设计理念时,就可以忽略子组件本次的 Render 过程。

PureComponent 和 React.memo 就是应对这种场景的,PureComponent 是对类组件的 Props 和 State 进行浅比较,React.memo 是对函数组件的 Props 进行浅比较。

useMemo、useCallback 实现稳定的 Props 值

如果传给子组件的派生状态或函数,每次都是新的引用,那么 PureComponent 和 React.memo 优化就会失效。所以需要使用 useMemo 和 useCallback 来生成稳定值,并结合 PureComponent 或 React.memo 避免子组件重新 Render。

useMemo 减少组件 Render 过程耗时

useMemo 是一种缓存机制提速,当它的依赖未发生改变时,就不会触发重新计算。一般用在「计算派生状态的代码」非常耗时的场景中,如:遍历大列表做统计信息。

显然useMemo的作用是缓存昂贵的计算(避免在每次渲染时都进行高开销的计算),在业务中使用它去控制变量来更新表格

shouldComponentUpdate

在类组件中,例如要往数组中添加一项数据时,当时的代码很可能是 state.push(item),而不是 const newState = [...state, item]。

在此背景下,当时的开发者经常使用

shouldComponentUpdate 来深比较 Props,只在 Props 有修改才执行组件的 Render 过程。如今由于数据不可变性和函数组件的流行,这样的优化场景已经不会再出现了。

为了贴合shouldComponentUpdate的思想:给子组件传props的时候一定只传其需要的而并非一股脑全部传入:

传入到子组件的参数一定保证其在自组件中被使用到。

批量更新,减少 Render 次数

在 React 管理的事件回调和生命周期中,setState 是异步的,而其他时候 setState 都是同步的。这个问题根本原因就是 React 在自己管理的事件回调和生命周期中,对于 setState 是批量更新的,而在其他时候是立即更新的。

批量更新 setState 时,多次执行 setState 只会触发一次 Render 过程。相反在立即更新 setState 时,每次 setState 都会触发一次 Render 过程,就存在性能影响。

假设有如下组件代码,该组件在 getData() 的 API 请求结果返回后,分别更新了两个 State 。

该组件会在 setList(data.list) 后触发组件的 Render 过程,然后在 setInfo(data.info) 后再次触发 Render 过程,造成性能损失。那我们该如何解决呢:

  1. 将多个 State 合并为单个 State。例如 useState({ list: null, info: null }) 替代 list 和 info 两个 State。
  2. 使用 React 官方提供的 unstable_batchedUpdates 方法,将多次 setState 封装到 unstable_batchedUpdates 回调中。

修改后代码如下:

精细化渲染阶段

按优先级更新,及时响应用户

优先级更新是批量更新的逆向操作,其思想是:优先响应用户行为,再完成耗时操作。常见的场景是:页面弹出一个 Modal,当用户点击 Modal 中的确定按钮后,代码将执行两个操作:

  1. 关闭 Modal。
  2. 页面处理 Modal 传回的数据并展示给用户。

当操作2需要执行500ms时,用户会明显感觉到从点击按钮到 Modal 被关闭之间的延迟。

以下为一般的实现方式,将 slowHandle 函数作为用户点击按钮的回调函数。

slowHandle() 执行过程耗时长,用户点击按钮后会明显感觉到页面卡顿。

如果让页面优先隐藏输入框,用户便能立刻感知到页面更新,不会有卡顿感。

实现优先级更新的要点是将耗时任务移动到下一个宏任务中执行,优先响应用户行为。

例如在该例中,将 setNumbers 移动到 setTimeout 的回调中,用户点击按钮后便能立即看到输入框被隐藏,不会感知到页面卡顿。mhd项目中优化后的代码如下:

发布者订阅者跳过中间组件 Render 过程

React 推荐将公共数据放在所有「需要该状态的组件」的公共祖先上,但将状态放在公共祖先上后,该状态就需要层层向下传递,直到传递给使用该状态的组件为止。

每次状态的更新都会涉及中间组件的 Render 过程,但中间组件并不关心该状态,它的 Render 过程只负责将该状态再传给子组件。在这种场景下可以将状态用发布者订阅者模式维护,只有关心该状态的组件才去订阅该状态,不再需要中间组件传递该状态。

当状态更新时,发布者发布数据更新消息,只有订阅者组件才会触发 Render 过程,中间组件不再执行 Render 过程。

只要是发布者订阅者模式的库,都可以使用useContext进行该优化。比如:redux、use-global-state、React.createContext 等。

业务代码中的使用如下:

从图中可看出,优化后只有使用了公共状态的组件renderTable才会发生更新,由此可见这样做可以大大减少父组件和 其他renderSon… 组件的 Render 次数(减少叶子节点的重渲染)。

useMemo 返回虚拟 DOM 可跳过该组件 Render 过程

利用 useMemo 可以缓存计算结果的特点,如果 useMemo 返回的是组件的虚拟 DOM,则将在 useMemo 依赖不变时,跳过组件的 Render 阶段。

该方式与 React.memo 类似,但与 React.memo 相比有以下优势:

  1. 更方便。React.memo 需要对组件进行一次包装,生成新的组件。而 useMemo 只需在存在性能瓶颈的地方使用,不用修改组件。
  2. 更灵活。useMemo 不用考虑组件的所有 Props,而只需考虑当前场景中用到的值,也可使用 useDeepCompareMemo 对用到的值进行深比较。

该例子中,父组件状态更新后,不使用 useMemo 的子组件会执行 Render 过程,而使用 useMemo 的子组件会按需执行更新。业务代码中的使用方法:

精确判断更新的’时机’和’范围’

debounce、throttle 优化频繁触发的回调

在搜索组件中,当 input 中内容修改时就触发搜索回调。当组件能很快处理搜索结果时,用户不会感觉到输入延迟。

但实际场景中,中后台应用的列表页非常复杂,组件对搜索结果的 Render 会造成页面卡顿,明显影响到用户的输入体验。

在搜索场景中一般使用 useDebounce+ useEffect 的方式获取数据。

在搜索场景中,只需响应用户最后一次输入,无需响应用户的中间输入值,debounce 更适合。而 throttle 更适合需要实时响应用户的场景中更适合,如通过拖拽调整尺寸或通过拖拽进行放大缩小(如:window 的 resize 事件)。

懒加载

在 SPA 中,懒加载优化一般用于从一个路由跳转到另一个路由。

还可用于用户操作后才展示的复杂组件,比如点击按钮后展示的弹窗模块(大数据量弹窗)。

在这些场景下,结合 Code Split 收益较高。懒加载的实现是通过 Webpack 的动态导入和 React.lazy 方法。

实现懒加载优化时,不仅要考虑加载态,还需要对加载失败进行容错处理。

懒渲染

懒渲染指当组件进入或即将进入可视区域时才渲染组件。常见的组件 Modal/Drawer 等,当 visible 属性为 true 时才渲染组件内容,也可以认为是懒渲染的一种实现。懒渲染的使用场景有:

  1. 页面中出现多次的组件,且组件渲染费时、或者组件中含有接口请求。如果渲染多个带有请求的组件,由于浏览器限制了同域名下并发请求的数量,就可能会阻塞可见区域内的其他组件中的请求,导致可见区域的内容被延迟展示。
  2. 需用户操作后才展示的组件。这点和懒加载一样,但懒渲染不用动态加载模块,不用考虑加载态和加载失败的兜底处理,实现上更简单。

懒渲染的实现中判断组件是否出现在可视区域内借助react-visibility-observer依赖:

虚拟列表

虚拟列表是懒渲染的一种特殊场景。虚拟列表的组件有 react-window和 react-virtualized,它们都是同一个作者开发的。

react-window 是 react-virtualized 的轻量版本,其 API 和文档更加友好。推荐使用 react-window,只需要计算每项的高度即可:

如果每项的高度是变化的,可给 itemSize 参数传一个函数。

所以在开发过程中,遇到接口返回的是所有数据时,需提前预防这类会有展示的性能瓶颈的需求时,推荐使用虚拟列表优化。使用示例: react-window​react-window.vercel.app

动画库直接修改 DOM 属性,跳过组件 Render 阶段

这个优化在业务中应该用不上,但还是非常值得学习的,将来可以应用到组件库中。

参考 react-spring 的动画实现,当一个动画启动后,每次动画属性改变不会引起组件重新 Render ,而是直接修改了 dom 上相关属性值:

避免在 didMount、didUpdate 中更新组件 State

这个技巧不仅仅适用于 didMount、didUpdate,还包括 willUnmount、useLayoutEffect 和特殊场景下的 useEffect(当父组件的 cDU/cDM 触发时,子组件的 useEffect 会同步调用),本文为叙述方便将他们统称为「提交阶段钩子」。

React 工作流commit阶段的第二步就是执行提交阶段钩子,它们的执行会阻塞浏览器更新页面。

如果在提交阶段钩子函数中更新组件 State,会再次触发组件的更新流程,造成两倍耗时。一般在提交阶段的钩子中更新组件状态的场景有:

  1. 计算并更新组件的派生状态(Derived State)。在该场景中,类组件应使用 getDerivedStateFromProps钩子方法代替,函数组件应使用函数调用时执行 setState的方式代替。使用上面两种方式后,React 会将新状态和派生状态在一次更新内完成。
  2. 根据 DOM 信息,修改组件状态。在该场景中,除非想办法不依赖 DOM 信息,否则两次更新过程是少不了的,就只能用其他优化技巧了。

use-swr 的源码就使用了该优化技巧。当某个接口存在缓存数据时,use-swr 会先使用该接口的缓存数据,并在 requestIdleCallback 时再重新发起请求,获取最新数据。模拟一个swr:

  1. 它的第二个参数 deps,是为了在请求带有参数时,如果参数改变了就重新发起请求。
  2. 暴露给调用方的 fetch 函数,可以应对主动刷新的场景,比如页面上的刷新按钮。

如果 use-swr 不做该优化的话,就会在 useLayoutEffect 中触发重新验证并设置 isValidating 状态为 true·,引起组件的更新流程,造成性能损失。

工具介绍——React Profiler

React Profiler 定位 Render 过程瓶颈

React Profiler 是 React 官方提供的性能审查工具,本文只介绍笔者的使用心得,详细的使用手册请移步官网文档。

Note:react-dom 16.5+ 在 DEV 模式下才支持 Profiling,同时生产环境下也可以通过一个 profiling bundle react-dom/profiling 来支持。请在 fb.me/react-profi… 上查看如何使用这个 bundle。

“Profiler” 的面板在刚开始的时候是空的。你可以点击 record 按钮来启动 profile:

Profiler 只记录了 Render 过程耗时

不要通过 Profiler 定位非 Render 过程的性能瓶颈问题

通过 React Profiler,开发者可以查看组件 Render 过程耗时,但无法知晓提交阶段的耗时。

尽管 Profiler 面板中有 Committed at 字段,但这个字段是相对于录制开始时间,根本没有意义。

通过在 React v16 版本上进行实验,同时开启 Chrome 的 Performance 和 React Profiler 统计。

如下图,在 Performance 面板中,Reconciliation和Commit阶段耗时分别为 642ms 和 300ms,而 Profiler 面板中只显示了 642ms:

开启「记录组件更新原因」

点击面板上的齿轮,然后勾选「Record why each component rendered while profiling.」,如下图:

然后点击面板中的虚拟 DOM 节点,右侧便会展示该组件重新 Render 的原因。

定位产生本次 Render 过程原因

由于 React 的批量更新(Batch Update)机制,产生一次 Render 过程可能涉及到很多个组件的状态更新。那么如何定位是哪些组件状态更新导致的呢?

在 Profiler 面板左侧的虚拟 DOM 树结构中,从上到下审查每个发生了渲染的(不会灰色的)组件。

如果组件是由于 State 或 Hook 改变触发了 Render 过程,那它就是我们要找的组件,如下图:

站在巨人的肩膀上

Optimizing Performance React官方文档,最好的教程, 利用好 React 的性能分析工具。

Twitter Lite and High Performance React Progressive Web Apps at Scale 看看 Twitter 如何优化的。

-END-

连续三年第一,数字广东有什么秘籍?

$
0
0

5月26日,国务院办公厅电子政务办公室委托中央党校(国家行政学院)电子政务研究中心编制的《省级政府和重点城市一体化政务服务能力(政务服务“好差评”)调查评估报告(2021)》(下简称《评估报告》)正式发布。省级政府一体化政务服务能力指数评估中,广东连续第三年得分居全国第一,摘得“三连冠”。

今年的《评估报告》广度和深度较往年明显提升,更加关注政务服务区域通办、跨省通办、线上线下融合、省市县协调联动等一体化能力建设,这与我国网上政务服务已经由以信息服务为主的单向服务阶段,开始迈向以跨区域、跨部门、跨层级一体化政务服务为特征的整体服务阶段密切相关。

时代提出新要求,广东表现更亮眼。《评估报告》显示,广东省在线服务成效度、在线办理成熟度、服务方式完备度、服务事项覆盖度、办事指南准确度五项指数得分均名列三甲,其中在线办理成熟度高居榜首。《评估报告》指出,广东大胆探索,因地施策,注重创新引领,以政务信息化体制机制优化为突破口,始终坚持政务服务移动化、一体化、精细化的发展方向,取得积极成效。

一体化平台建设,促进广东省政务服务质量跃升

《评估报告》显示,广东一体化政务服务能力总体指数达到“非常高”,一体化平台建设三年来不断升级。依托一体化政务服务平台,供给群众和企业的创新服务、精准服务越来越多,协同服务、整体服务能力越来越强。

政务服务的办事流程更加“一体化”。以电子证照的推广应用为例,2018年,广东率先与国家一体化在线政务服务平台实现全面对接,逐步实现“应接尽接、应上尽上”。2019年,依托一体化平台,广东对近5000项高频服务事项实现电子证照关联。

2020年,完成电子证照关联的高频事项增至1.6万项,超过200项“一件事”主题集成服务只需交“一张表单、一套材料”。目前,广东省级部门 “零跑动”事项超98%,地市级超92%,县区级超86%,全省“最多跑一次”事项超98%。

线上线下的政务服务更加“一体化”。广东在全国率先探索政银合作模式,全省各商业银行超过2万台自助终端变成了线下的政务服务一体机平台,在社区村居就可以就近办理高频政务服务事项。完善推广“前台综合受理、后台分类审批、综合窗口出件”的一窗通办模式,打造政务服务大厅事项管理、综合评价、人员服务标准体系。

跨地域的政务服务更加“一体化”。广东全力推动政务服务“跨省通办、省内通办、跨境通办”,在全国率先推出泛珠区域“跨省通办”服务专区,目前16个地市与泛珠九省区实现3644项高频事项线上线下多渠道跨省通办。初步建立粤港澳大湾区身份认证、电子证照等信息资源共享互认机制,推进粤港澳“湾区通办”。

一体化平台建设带动全省政务服务能力跃升,经受住疫情考验。新冠肺炎疫情发生以来,广东依托国家一体化平台,第一时间建立防控数据共享机制,汇聚从国家到地方约75亿条数据,助力基层抗疫“摸清底数”。同时,第一时间在粤省事上线“疫情防控服务专区”,“粤康码”成为居民防疫的“身份证”和“通行证”。“粤康码”率先与国家健康码实现互认,并且在2020年7月仅用 10天就完成粤澳健康码互转互认,成为全国首个实现跨境转码互认的健康码,为我国在国内及与世界各国开展疫情联防联控积累了宝贵经验。

持续创新“粤系列”平台应用

企业和群众的使用需求,决定了移动化是政务服务提供方式的大势所趋,广东坚持用户思维,针对群众、企业、公职人员群体的不同办事需求,建立粤省事、粤商通、粤政易移动平台,形成“粤系列”移动政务服务品牌。

2018年创新推出的粤省事移动政务服务平台, 现已集成原有分散在各部门的1753项服务事项及90种个人电子证照,动动指尖就可以轻松办理社保、公积金、养老、出入境以及交通出行等服务。

2021年1月1日起,全省所有助产机构分娩新生的母亲,都可以通过粤省事出生医学证明网上申领功能足不出户领到小孩的“出生证”。这样的 “零跑动”事项,粤省事目前有超过1259项,享受这些服务的实名用户突破1.2亿。

粤商通涉企移动政务服务平台将分散在47个省级部门1163个高频服务事项和158类涉企常用电子证照集成到移动端,支持企业“一站式、免证办”,政商关系“亲上加清”。

粤商通不仅围绕市场主体的全生命周期,集中提供覆盖各行业的涉企政策和资讯服务,而且可以根据企业“画像”定向推送政策资讯、对接资金渠道,更为每个市场主体打造唯一的“粤商码”,企业信息由必须携带各种材料“多证检验”,变为拿出手机“亮码可见”。 目前,在粤商通注册的市场主体数超755万,超过广东市场主体总数一半。

粤政易移动办公平台则让广东公职人员线上办公成为常态,“整体政府”建设稳步推进。目前粤政易已基本覆盖全省五级公职人员,实现跨部门、跨层级业务协同,文电办理用时比以前下降约40%,部门行政效率大幅提升,业务管理更加扁平高效。

放眼全国,“粤系列”平台用户规模、服务覆盖范围和活跃度均遥遥领先。2021年5月,《广东省数字政府移动政务服务平台(粤系列)管理办法》出台,明确“粤系列”平台的建设和管理应遵循统建共管、整体联动、开放融合、赋能发展的原则,进一步推动全省各级各类移动政务服务平台的资源整合、规范管理。

政务服务往精细化、智慧化发展,体现浓浓人情味。当老年人的“数字鸿沟”困扰公众时,广东全面开展政务服务适老化改造,粤省事上线全国首个移动端适老化老年人服务专区——“尊老爱老服务专区”,大字体、宽间距的界面、刷脸一键登录、语音搜索,都对不擅长操作手机的老年人十分友好。此外,“粤康码”核验流程的优化、老年人出示身份证亮码通行、政务服务大厅专设“绿色通道”等,更在线下线上合力帮助老年人跨过“数字鸿沟”。 

强化数据资源共享和开发利用

持续深化改革,敢于全国先行,是广东三年来政务服务能力实现跃升,数字政府建设不断突破的关键。如何在政务服务过程中让数据取之于民、用之于民、更利之于民,如何推进数据要素市场化配置改革,则是广东当前数字政府建设重点思考的问题和大胆探路的方向。

首先是集聚“数据资产”,逐步共享开放。广东部署开展全省政务信息能力和公共数据资源普查,形成系统和数据资源全省一本账,摸清数据资产的底数。全面建成省级数据中台,归集数据超过258亿条,建成“数据宝库”。通过“开放广东”平台统一向社会开放资源环境、教育科技、交通运输等12个领域的政务数据。同时,制订数字政府数据开放重点和开放计划,为进一步的共享开放打下基础。

更重要的是系统完善数据领域法规制度。印发《广东省公共数据资源开发利用试点实施方案》,编制完成《广东省数据要素市场化配置改革行动方案》,起草《广东省公共数据管理办法》和《广东省公共数据开放暂行办法》,并在21个单位开展公共数据资源开发利用试点,下一步还将推进《广东省数据条例》立法起草工作。

近日,广东在全国首创首席数据官(CDO)制度,印发《广东省首席数据官制度试点工作方案》,在全省选取6个省直部门以及10个地市,设立专属职位与制度,负责各部门之间数据协调处理与共享开发利用,令数据的共享、共治更具条理与深度,对实现全社会数据资源高效开发利用具有先锋意义。

省市数字政府建设协同提升

近年来,广东大力推进区域协调发展,而受区域经济发展不平衡影响,各地市的数字政府建设不均衡的问题始终是全省的一大挑战。坚持“全省一盘棋”,支持各地市数字政府建设协同提升,对广东取得数字政府建设持续取得突破,对全国的数字政府均衡发展的经验积累都至关重要。

2020年,广东创新建立“省市联建”模式,省统筹资源大力支持汕尾、汕头、湛江等欠发达地市数字政府基础设施建设和政务应用建设。同时,支持珠三角地区开展改革创新,在广州市越秀区创建全省数字政府改革建设示范区。珠三角的改革创新经验在全省复制推广,降低欠发达地区的试错成本,从而让珠三角地区和欠发达地区的能力协同提升。

在信息基础设施和应用水平方面,全省统筹推进,支持欠发达地区数字政府建设“弯道超车”。省财政统筹安排资金支持地市政务云设施和政务外网建设,支持欠发达地市建设政务大数据中心和数据分析平台。

将改革探索转化为建设经验

三年间,广东群众企业逐步告别“办事难、办事慢、办事繁”,社会治理更加智慧化、现代化,数字政府建设不断向纵深拓宽的背后,是广东省始终坚持以人民为中心的根本立场,坚持需求导向、问题导向的用户思维,坚持互联网思维,始终坚持改革创新。

广东不仅善于锐意改革,积累经验,也善于总结经验,运用经验。在总结过去几年数字政府建设的基础上,广东正全面推进数字政府标准化建设。近期,广东制定《广东省“数字政府”标准化工作管理办法(试行)》,“互联网+政务服务”标准规范、电子证照标准规范、“数据治理”标准规范、“数字政府”应用平台系列标准、政务服务大厅建设与运行管理系列标准等重点标准规范将陆续落地,现已构建包括314项标准规范的数字政府标准体系框架。

在标准化的保障和“三连冠”的提振下,广东数字政府建设稳步开启“十四五”新征程。省政府副秘书长、广东省政务服务数据管理局局长杨鹏飞透露,“十四五”期间,将继续坚持“全省一盘棋”思路,在整体规划的基础上继续打破行政壁垒和信息孤岛,持续深化政务服务“一网通办”,推动省域治理“一网统管”,强化政府运行“一网协同”,并最终实现“三网”融合,打造“数据+服务+治理+协同+决策”的政府运行新范式。

此外也立下了一个目标:到2025年全面建成“智领粤政、善治为民”的“广东数字政府2.0”,为千家万户提供更优质的民生服务,为政府治理现代化提供更有力的信息化支撑。雷锋网雷锋网雷锋网

为什么说所有活下去的大企业,终将成为平台型组织?

$
0
0

本文作者:穆胜,原标题《组织模式进入平台纪元》,头图来自:视觉中国

  

一、为什么要做组织转型?


组织转型无疑需要投入巨大的成本,也并不是一场必胜的出征,那么,为什么企业还痴迷于此呢?根据我这些年来与企业的大量接触,总结起来应该有三点原因:

 

第一个原因是慢慢滋生的大企业病让老板们不安。

 

所谓大企业病,就是企业长大以后的官僚化,用现在流行的一个词语来描述,就是“内卷”。

 

这些官僚的形态可以描述为四类——部门墙、隔热层、流程桶、指标真空罩。这些现象,真正在企业待过一段时间的人应该都有感觉。

 

  • 部门墙——横向协调困难,调不动资源。每个部门只做自己一亩三分地的事,多走半步也不愿意,自己的事情又越做越少,部门之间出现了一堵堵厚厚的墙。


  • 隔热层——纵向沟通阻滞,说不清授权。上级要么迷恋权力,要么不敢授权,由于上下级权力分配没有说清楚,市场的信息上不去,上级的决策下不来,老板被“困死”在办公室里。


  • 流程桶——流程环节无限复杂,一个节点停滞,整个链条停滞。流程越多效率越低,流程里的每个节点都变成了更大的官僚。


  • 指标真空罩——这是我提的一个概念,就是说虽然分解了KPI,但这些KPI与公司战略没有多大关系,反而变成了每个人保护自己的真空罩,一句“我已经完成了我的工作”就万事大吉。

 

所有这些官僚主义,都让企业内员工的创造力和各类资源被封死,无法创造价值。这些内卷,所有人都能感觉到,但老板们一定是最痛的,所以他们会走向组织转型。但有人也会问,为什么还有大量老板不为所动呢? 

 

这个也很好解释。这些老板相信,只要还有人力资源管理中的绩效评价,任用好人、淘汰坏人,员工依然会被驱动,组织就坏不了。即使现有绩效评价的结果大多没有区分度,呈现纺锤体分布,只要在头部推优推模、尾部鞭打后进,整个组织的风向就不会太差。

 

图1:绩效评价的纺锤体分布图

资料来源:穆胜企业管理咨询事务所

 

另外,加上一些HR们实施的晋升诱惑、降级威胁、组织关怀、科学算命(大量理论分析和概念包装,说的都是不用分析就知道的事),组织也应该是井井有条的。还是那句话,只要组织大风向不乱,行业有基本的利润率,业绩就差不了,也兜得住人工成本预算,不就是人效低一点吗?

 

这样的看法肯定是有问题的,而且这种问题在互联网时代会暴露无遗。这就是让老板们下决心做组织转型的 第二个原因——悄悄逼近的“管理双杀效应”。


我们发现,企业的成长会经历生命周期的三个阶段。

 

第一个阶段是车库创业期,企业凭借创始团队的组织活力脱颖而出,实现增长。

 

这个阶段是可以“弱管理”的,因为团队小,每个人都是无限补位,且不计较暂时的回报。大家心中都有一个想法,把企业做上市,实现财务自由和人生价值。

 

当然,我这里也要提醒各位处于这个阶段的老板们,这个时间窗口只有7年左右。这来自于我的观察,我对这个数字相当肯定。

 

道理很简单,每个联合创始人或高管对一个创业项目的热情大概会持续3年,除非项目持续往上走,给他们更大的期待。

 

而初创团队如果没有一飞冲天,基本就只能通过老板透支信用的方式再折腾一轮,引入新的团队再来个3年。这样一共就是两个3年,中间还有1年的切换期,这就是7年。

 

所以,如果没有在7年里找对战略方向,企业基本就会一直平庸,因为后来进来的人就是职业经理人心态了。战略没有找对的前提下,人才也更平庸了,企业的发展前景如何,就不用多说了。

 

第二个阶段是缓冲期,企业已经发展到了一定规模,可以凭借规模经济的优势实现增长。

 

规模经济的爆发力非常强,这个时候企业会走上业绩快车道。但是,由于规模增加了,人员也增加,分工更细,层级更多,流程更复杂,KPI无处不在,大企业病一定如约而至。

 

第三个阶段如何定义完全在于企业的选择,做好了就是蝶变期,做不好就是花样作死期。

 

这个阶段,因为大企业病,规模经济的效应已经触顶,而大企业病却愈演愈烈,完全没有下限。于是,企业有两条路可以选择,要么根除疗法,也就是组织转型;要么保守疗法,也就是维持现状,小修小补。

 

图2:“管理双杀效应”示意图

资料来源:穆胜企业管理咨询事务所

 

问题来了,企业如果要保守行不行呢?我的答案是否定的。

 

过去,企业可以平庸生存,但互联网与数字化时代,并没有给平庸企业太多生存空间,即使现在有,也可能因“全域竞争”的来临而消失。

 

另外,即使能够躲在“角落”,企业也会被封死上限,随着产业的衰亡而衰亡,无法寻找第二曲线。这并不是一个明智的选择。

 

当然,还有一个思路是,有的企业在前一个阶段冲得很猛,希望进入第三阶段后能够“大而不倒”。

 

但你不得不关注到 “管理双杀效应”,即人效的下降会降低财效,财效反过来又拉低人效,双向拖低,导致企业轰然倒下。

 

根据我们的研究, 互联网属性的企业里,人效对于财效的影响是4倍以上的关系,即人效提升或降低1个单位,财效提升或降低4个以上的单位。

 

现实是,规模效应释放越大,“管理双杀效应”来得越猛,你驾驭不了的规模,可能是你的索命符,典型代表就是是凡客、乐视、ofo、瑞幸等企业。

 

我想,这可能也是部分看懂了时代的老板选择组织转型的原因,他们无法承担坠落,又不甘于平庸,所以会在缓冲期提前做好准备,期待在蝶变期一飞冲天。

  

第三个原因是互联网时代的不确定性,无处不在的黑天鹅和灰犀牛。


这两个词大家应该都不陌生,黑天鹅事件指难以预测但有重大影响的事件,而灰犀牛指人们习以为常但有重大影响的事件。

 

中国的企业近年来已经遭遇了太多的黑天鹅与灰犀牛,行业政策性抽贷、最严格环保政策、中美贸易战、新冠疫情等,无一不让企业头疼,在这些不确定性中倒下的企业也不少。

 

尤其是这次的疫情,开始让老板们痛定思痛——如何才能建立一种有韧性的组织?

 

我们可以思考一下,一边是精心修剪的花园,一边是亚马逊热带雨林,哪个生态系统更有韧性?答案显而易见。原因是,热带雨林里的每个物种都不是规划出来的,他们深深扎根于环境,还相互滋养,具有极强的自我修复能力。

 

所以,我们能不能让组织也变成热带雨林,让每个模块变成一家公司,让他们完全基于市场环境(客户和资源)来生长呢?

 

这可能帮老板们下了最后的决心。

 

上述三个动因,老板如果被一个击中,都会走向组织转型。而正如英特尔前首席执行官安德鲁·格鲁夫所言—— “纵观任何一家企业的发展历史,至少会出现那么一个时刻,你必须做出巨大的改变,才能将业绩提升到更高的水平。错过这一时刻,你就会开始走下坡路。”

 

我们看到的是,留给企业的时间窗并不大,如果在缓冲期里不调整管理,不准备组织转型,企业就前途堪忧。

 

我们也不妨回想中国企业的两棵常青树——海尔和华为。两家企业都是在1998年迅速上规模时开始调整管理,随后,他们都走向了平台型组织。而这种打磨管理的诚意让他们收获了如今的成功。

 

以华为为例,1998年,他们引入了IPD(集成产品研发系统),而在2008年,中兴通讯才引入了相似的HPPD(高效产品研发系统),而至今,两家企业的营收差距已经是7000亿人民币左右。


图3:华为&海尔组织转型历程

资料来源:穆胜企业管理咨询事务所

 

二、为什么是平台型组织?

 

种种动因之下,企业开始走向组织创新或组织转型。他们最初的想法都很朴素——拆掉金字塔组织,让每个组织模块,甚至每个个体都能够充满动力,让人人都是自己的CEO。

 

在这样的思路下,平台化、扁平化、无边界组织、去中心化、去权威化、自组织、小团队作战……等口号铺天盖地,企业也开始了各种各样的组织创新实践。

 

其实,早在2010年前我就注意到了这种变化,并投身其中做了大量的研究。

  

最初,每个案例的出现都让我们眼前一亮,让我们以为是发现了新物种。其实,这种状态肯定是不对的,如果看完了100个样本,在我们的眼中还是100个,只能说明我们没有看懂呀,因为我们没有找到共同的“模式”!后来看得越多,我就越看出了门道,发现了一些问题。

 

我不想否认这些企业在组织创新上的一些精彩实践,但我认为,有三类过于浪漫的错误尝试是不靠谱的:

 

第一类思路是个体激励,即认为激活个人就是激活组织,于是设计各种激励方案来让员工“动起来”。具体表现有几种:

 

  • 无限细化绩效——好多老板都在幻想这样一种状态,即最好全公司都实现数字化,把每个人都变成美团快递小哥,白天干活,晚上就能数钱。要达到这种状态,一方面需要企业实现完全的数字化,否则根本没有数据来核定绩效;另一方面需要流程实现完全的标准化,否则定价成本会奇高。显然,这很难实现,这种想法是幼稚的。


  • 全员股权激励——有的老板在公司上上下下都给股权,号称要把公司变成大家的。股权只能给一小部分创造最大价值的人,全员股权激励肯定是个错误。各位清醒一下吧,如果全员股权激励能成功,股权式众筹早就成功了。有人还拿华为举例子,我告诉各位,华为的成功并不是股权激励的成功,而是他们的IPD、ISC、IFS等组织模式层面的苦功夫。而他们的股权激励工具TUP,也是改造之后的一种类股权激励。就算如此,他们几年前还大量降低了TUP分享的额度,只把钱发给项目里那些做事的人。


  • 悬赏英雄模式——这也是大多老板的一个定向思维,他们发现了市场机会,于是设定目标,高额悬赏,期待英雄辈出。但各位不妨想想,如果一个英雄在公司的高额悬赏之下凭借一己之勇气获得了成功,这意味着什么?我认为,这是他个人的成功,也是公司的失败。公司投入试错成本,让他相信了自己不用借助公司的太多支持,就能把一个事业做成。公司送了他一个机会,他回头就可能送公司一个自由,人家不和你一起玩了。但人家这样做也可以理解,毕竟公司的体系并没有为人家提供增量嘛!


第二类思路是想要把市场力量引入内部,即认为只有真金白银的交易才能传递市场压力,于是设计了各种形式的内部交易。具体表现有几种:


  • 内部交易模式——即研产销等部门进行上下游交易,要求按照“下道工序就是用户”的标准进行交付。最典型的是阿米巴模式,在1998年左右,海尔也尝试过相似的实践,叫“内部市场链”。但我一句话就可以捅破这种模式的BUG,经济学原理告诉我们,当市场只有一个出价者和一个受价者的时候,价格是说不清楚的。说不清价格的情况下,阿米巴之间反而会形成更厚的墙。


  • 大中台模式——这是近几年新兴的一种趋势,不少企业希望建设大中台,打造资源超市,让前台随需调用。如果中台向前台输送的补给能够标准化,那么定价也不是难题。基于这种交易关系,前台在市场的压力之下会拉动中台,市场力量就传递了进来。但根据我们的观察,这也是不靠谱的,建设资源超市的难度首先就太大,而大中台更不可能为小前台做改变,于是,他们反而成了更大的官僚。

 

第三类思路是以情怀替代制度,企业家以己度人,想要让每个人都拥有创业精神。具体表现有几种:


  • 价值观考核——这是几乎所有老板内心都会保持的一个执着,他们模仿巨头企业的做法,希望通过价值观行为化,行为分级化,来实现考核。但他们也不妨去这类企业里看看,这种考核会导致什么样的结果。这叫“行为锚定法”,只要玩过这种考核模式的人都知道,这种考核不会形成区分度。两个周期的考核之后,考核成绩的分布就会平均化,大家的行为都会稳稳停留在60分,于是,这部分考核的权重就失去了意义。价值观肯定非常重要,但不应该用这样的方式来应用。


  • 寻找街头创新——各种冠以炫酷名词的创新大会。说白了,就是让员工贡献各种创意,再给一定的权限和资源,让员工带着创意去落地,如果做得不错,还有一笔奖金。但创新基本上都只会在非主赛道上发生,因为主赛道的资源你撼动不了,激励自然也不会到位,于是,最后的结果是不了了之。

 

我从这些错误中总结了几个判定组织创新真伪的定律:

  

  • 定律1——不应把企业“原子化”,应该在激活系统的前提下激活个体。只要穿透系统直接谈个体激励的,就都是伪命题。


  • 定律2——不应进行串联,而应进行并联,共同面对用户。只要以交易形式进行“内部市场化”的,就都是乌托邦。


  • 定律3——情怀不能替代制度设计,凡是需要用情怀来弥补BUG的制度,都是无效制度。好的制度应该可以让最“坏”的人变“好”。


基于这三个定律,我们也可以推演出真正的创新组织模式的几个特征:

 

  • 灵活聚散——根据市场需求,由合适的员工迅速组合成为最适配的团队。几乎可以肯定的是,新的组织模式一定是柔性的,部门、团队、岗位的边界一定是模糊的。


  • 并联劣后——灵活聚散而成的团队一定是紧密连接、动机一致、不留余力的,这里就必须有劣后条款的设置来绑定大家的利益,说俗点,就像大家一起做生意一样,公司不好,几个股东也都不会好。


  • 用户付薪——员工的收益来自为用户创造的价值,中间没有损耗。换句话说,不是公司用预算给员工付钱,而是员工自己从市场上挣钱。

 

其实,谈到创新的组织模式,我们根本不用去考虑员工的动机问题,因为没有员工是天然的对抗者。我们只需要聚焦思考企业需要提供什么样的环境——什么样的企业会让员工变成创客?

 

我认为,这样的企业应该像一个平台,平台之上能长出若干的经营单元。具体来说,这类平台应该有三层:

 

一是资源洼地,即企业有创客能够利用的廉价优质的资源,让创业的起点更高。

 

二是共享机制,即创客在平台上的贡献,能够获得相对外部其他平台和内部金字塔组织更为合理的回报。

 

三是价值理念和战略内核,即平台有共同的价值观和共同的战略内核,能够定义出底层的游戏规则。

显然,资源洼地、价值理念、战略内核都是既定的,有就有,没有就没有,我们能做的就是通过组织转型或组织创新,让这些既定的要素形成平台,让企业走向一种全新的组织模式——平台型组织(platform-based organization)。

 

图4:平台型组织的四大构件

资料来源:穆胜企业管理咨询事务所

 

三、如何实现组织转型?

 

所有的猜想都必须落到实践里去验证。

  

让一个企业从金字塔组织变成平台型组织,关键要解决员工的“责、权、利、能”这四大要素,并合并为三大变革:

 

其一,重塑组织结构,也就是重新定义“责”和“权”。这将改变指挥条线,让小业务团队甚至个体开始以用户为中心,让听得见炮火的人来决策,让前台调动中台再调动后台。

 

其二,重塑激励机制,也就是重新定义“利”。这将改变指挥条线上每个节点的利益分配方式,让人人都为自己打工。

 

其三,重塑人才供应链,也就是重新塑造“能”。平台型组织对于个体能力的要求是极高的,因此,转型平台型组织的企业无一例外都会发现自己的人才缺口,于是要求我们帮助他们打造出高效率和超稳定的人才供应链。


值得一提的是,这也是我们在近两年的实践中观察到的现象。我相信,直到现在还有很多人以为平台型组织中的人才是依靠learn by doing来实现成长的。显然,这样的想法很幼稚。

 

平台型组织必须实现人才量产,而实现人才量产的方式一定是做知识管理,只有基于强悍的知识管理,人才才能批量化复制。

 

所以, 我建议借由当下企业大学“去大学化”的政策调整,企业将自己的大学改名为“知识管理(赋能)中心”,这将是TD和LD们职业生涯的又一个大舞台,甚至比原来的舞台还大。

 

上述的三大转型并不容易,因为每个转型都是在挑战企业原有的组织与人力资源管理体系:

 

  • 新的 组织结构意味着,人员以BP形式相互嵌套,跨边界作战,岗位职责无限延展,这显然挑战了原有分工清晰的组织结构。


  • 新的 激励机制意味着,员工获得“分享利润”程度的激励水平,这显然挑战了原有“岗位工资+绩效工资+奖金”的传统三段式薪酬。


  • 新的 赋能机制意味着,员工在平台上能够获得四面八方的知识补给,能够快速上手,灵活纠错,这显然又挑战原有“教-学”式的培养逻辑。

 

各位朋友,经过了这么多年对于组织转型和组织创新的研究与实践,我们可以自称是“深耕于此,精于此道”了。

 

正因如此,我们才会对于企业走向平台型组织的趋势异常肯定。 这不是小修小补,而是一个新时代的开始,组织模式已经进入平台纪元,而在座各位都将是这个新时代的见证者。

下载虎嗅APP,第一时间获取深度独到的商业科技资讯,连接更多创新人群与线下活动

Oracle 各种删除操作对空间返还的说明

$
0
0

标签:   oracle   空间

Oracle 各种删除操作对空间返还的说明
操作表空间是否回收空间?文件系统或ASM是否回收空间?是否造成表上的碎片?在本地管理表空间(LMT 9i以后)是否造成表空间碎片?在字典管理表空间(DMT 9i以前)是否造成表空间碎片?注意现在的oracle版本不太可能用DMT是否造成索引碎片?有心理问题,或者为应付领导,一定要对付对付不存在的碎片怎么办?
DELETE SQL否,空间可以被该表重用。可以称之为高水位,但谈不上碎片不适用不适用对表可以shrink space;对索引可以coalesce操作;对于大表而言IO和redo会很多,耗时也可能长
DROP TABLE是的;视乎recyclebin参数是否进入回收站;但空间都可以被表空间重用都没表了本地管理表空间的extent是统一大小或系统自动分配大小,不存在表空间碎片可能导致碎片(alter tablespace coalesce适用场景)索引都没了不适用
TRUNCATE TABLE默认是的本地管理表空间的extent是统一大小或系统自动分配大小,不存在表空间碎片可能导致碎片(alter tablespace coalesce适用场景)不适用








注:Oracle除非手动resize datafile,否则一般不会自动返回空间给文件系统或ASM

   


您可能还对下面的文章感兴趣:

  1. 裁剪和空间管理 [2021-05-27 07:52:49]
  2. 修改Linux交换空间的使用率 [2018-07-05 13:32:32]
  3. 使用 Ubuntu Cleaner 为 Ubuntu/LinuxMint 释放空间 [2017-12-24 19:51:34]
  4. 给代码多留一些空间 [2014-06-10 12:26:47]

《红楼梦》开始于《金瓶梅》结束之处,再加上《水浒传》就是全部人性 | 专访

$
0
0

刘晓蕾与新作《作为欲望号的金瓶梅》

记者 | 潘文捷

编辑 | 黄月

年轻时看《金瓶梅》,刘晓蕾觉得不论是人物还是文字都“太粗粝”,到了三十多岁再次捧起《金瓶梅》时,她却感受到了“满篇锦绣”。

兰陵笑笑生所著的《金瓶梅词话》到如今已经拥有超过四百年的历史。它一直是世人眼中的“奇书”,展现了上至朝廷内擅权专政的太师,下至地方官僚恶霸、市井地痞、帮闲的世界,市井的丰富、人性的善恶和明代社会的黑暗尽逐显露。此书虽因恣肆铺陈的性描写而一直被视作“淫书”,却受到不少学者和作家的喜爱。此前,著有《秋水堂论金瓶梅》的哈佛大学东亚系中国文学教授田晓菲、著有《雪隐鹭鸶 : <金瓶梅>的声色与虚无》的清华大学中文系教授格非等人,都认为《金瓶梅》要胜过《红楼梦》。

那么,我们究竟该怎么进入《金瓶梅》?刘晓蕾是南京大学中国现当代文学博士,任教于北京理工大学,在学校开设了“《红楼梦》导读”公选课,曾被评为“最受欢迎的公选课教师”。2019年曾出版《醉里挑灯看红楼》,今年,她又推出了《作为欲望号的金瓶梅》一书。在这本书里,她不仅围绕“欲望”这一核心讲解了《金瓶梅》的独特之处,也邀请读者一道将《水浒传》和《红楼梦》对照阅读,她认为,从《水浒传》到《金瓶梅》再到《红楼梦》,背后反映的是文明发展的不同阶段。

01 把《金瓶梅》看作小黄书和“老婆舌头”,是一种“呆看”

界面文化:你的这本新书名为《作为欲望号的金瓶梅》,为什么给书起这个名字?

刘晓蕾:《金瓶梅》有多重的主题,比如欲望、商业、城市、死亡等,但如果只能用一个词来概括的话,那就是欲望。欲望本身是在城市和商业的条件下展开的,死亡也是在欲望的背景下展开的。

《金瓶梅》插图

界面文化:《金瓶梅》分成词话本和绣像本,美国汉学家和翻译家芮效卫(David Tod Roy)花了40年时间翻译成外文的是词话本,很多海外学者也觉得词话本是比较有艺术价值的。在你看来,为什么他们会更偏爱词话本?你自己是怎样的态度?

刘晓蕾:国外情况我不是很了解,国内好多人喜欢词话本可能是因为它保留了很多民俗资料,比如说一些美食和曲词(当时的流行歌曲)等等,读者能从词话本里看到当时的娱乐、饮食方方面面,看到民间活泼的文化,具有研究价值。绣像本把这些内容删掉了大部分,也是有自己的文学考量的。喜好哪个版本跟个人的阅读经历有关系。《红楼梦》也有不同的版本,大家各有所好,比如白先勇特别喜欢程乙本,因为那是他人生中接触《红楼梦》的第一个版本,有额外的感情。我第一次读《金瓶梅》就是绣像本。

我看《金瓶梅》不是从史料、民俗风情角度去观察,而是从人性、从文学的角度去观察,显然在这方面绣像本更有文学的自觉性。再把《红楼梦》拿来比较,曹雪芹对文学的主题、作品的结构、人物的设定是有自觉意识的,他知道自己要写的是一部不朽名著。《金瓶梅》词话本的作者似乎就不太在意这些,就是凭着自己的泼天才气,甚至有点偷懒。比如第一回,词话本一开头就把《水浒传》里武松的故事直接移植过来,而绣像本的修改者显然清楚《金瓶梅》的男主角是西门庆,而不是武松,于是改成了“西门庆热结十兄弟 武二郎冷遇亲哥嫂”。

界面文化:这是不是说明其实兰陵笑笑生写得没有那么好,修改过的更好?

刘晓蕾:不能这么说。词话本就像一个不太懂得打扮自己的绝世美女,出场不穿礼服,穿个衬衣牛仔裤就跳出来了。但是绣像本懂得修饰一下,知道画一画眉毛,点一点口红,马上就仪态万方。话又说回来,如果没有词话本这个美女的底子,绣像本再修饰也不行嘛。

绣像本第一就是把那些重复性的曲词、美食删掉,把一些偏口语化有点啰嗦的东西修整好;第二删掉了一些说教性的套话以及民间说书的术语,这样就比较文雅;第三有主题上的升华,尤其是第一回改得特别厉害。比如卷首诗,原来是“丈夫只手把吴钩,欲斩万人头。如何铁石打成心性,却为花柔”,绣像本是“豪华去后行人绝,萧筝不响歌喉咽”,表达的是更深邃的“空”与“悲”,直接抵达生命的本质,这比词话本的道德说教显然境界更高。当然,这不是绣像本修改者凭空添上去的,修改者深刻地体会到了词话本要表达的深层主题,凝练出来放在卷首。

刘晓蕾(受访人供图)

界面文化:你在书里引用了清代文学评论家张竹坡的话,“读《金瓶梅》,不可呆看,一呆看便错了”,什么叫“呆看《金瓶梅》”?你遇到过这种情况吗?

刘晓蕾:“呆看”就是人云亦云。比如说一想到《金瓶梅》,就认为它是一本“小黄书”,脑子里只有那几回著名的不太节制的文字,这是一种“呆看”。还有一种就认为写的是西门庆和他的女人们,如何吃饭如何上床如何吵架,满篇的“老婆舌头”,也就是八卦。还有人把《金瓶梅》看成西门庆家的账簿,关注今天花了多少钱,明天又花多少钱,米多少钱,猪肉多少钱,这些都是“呆看”。其实在表层日常生活的背后,有最严肃最深邃的主题。

02 大手笔兼细心思:《金瓶梅》关乎人性、道德、商业与宗教

界面文化:张竹坡说《金瓶梅》是“大手笔”但却是“极细的心思做出来”的。在你看来,“大手笔”和“极细的心思”体现在哪里?

刘晓蕾:首先说“大手笔”。大手笔是包罗万象,有广度,此外对人性的理解也有深度,作者站位也有高度。

《金瓶梅》是有头有尾的100回,里面人物有几百位,不光有西门庆和他的家里人,还以清河县为枢纽,细致地写出了商业社会的结构、城市生活的面貌,牵扯的面非常广。书中有从南方来的客人,西门庆的伙计也会到南京、杭州、苏州采买货物。清河县还有太监、大户以及各路官僚,甚至笔触还伸到了东京朝廷……除了市井生活,商业官场多有涉猎,让我们看到整个时代的氛围。

《金瓶梅》插图

除了群像,对每个个体的具象摹写也是大手笔。我认为,西门庆、潘金莲、应伯爵等等这些人都是前所未有的真实和深刻。如何理解这些人,就是如何理解欲望、人性、道德和商业。

从西门庆身上你可以看到,一个男性是如何在金钱和权力的加持下把欲望挥洒到极致的,还能看到他怎么做生意,他的生活和他的信仰,这样一个人身上有很多值得我们考量和深思的。我们也可以从潘金莲这个人物看女性的欲望,看到一个女人在欲望的驱使下是怎样“黑化”的,但这个狠辣的女性身上也有人性的一方面,甚至她相当聪明、性感——中国作家中很少有人把女性的恶与美写得如此酣畅,如此复杂。好多人讨厌应伯爵,一般都说他是个帮闲,骂他丑恶。田晓菲为他说过一句公道话,说“虽然他是个寄生虫,但我还是挺喜欢他的”(大意如此),但她也没多说。我在书里就为应伯爵专门写了一篇万字长文,从商业和城市的角度来看,你就会发现,应伯爵哪里丑恶?他就是一个中介,为西门庆做了很多服务,一个成熟的商业社会应该承认中介的作用。而且他特别会说话,情商特别高,在现代社会绝对是一把好手。

再说“极细的心思”。我读《金瓶梅》时常常对书里的细节流连忘返。作者是一个对生活、对人性充满好奇心的人,把握细节的能力非同凡响。

界面文化:可以举例说说吗?

刘晓蕾:第23回,潘金莲、孟玉楼和李瓶儿下棋,李瓶儿输了五钱银子,潘金莲就让人拿钱去买了猪头,再让宋蕙莲去烧。宋蕙莲一开始不愿意,因为她那时候是西门庆的情人了,以为自己也有身份了,能跟西门庆的小妾说得上话了。但旁边有人让她赶紧去,五娘那个脾气你是知道的,她只好去下厨。作者写她把猪头弄干净,抹了酱料,然后放上锡古子(类似于现在的高压锅),用一根柴火,把猪头烧到皮脱肉化,香喷喷的,用冰盘盛上来。还是李瓶儿让人盛了一碟给宋蕙莲,她就在一旁站着吃了。这个小细节充满心思,这是后院里的“宫心计”,有潘金莲和宋蕙莲的较劲,有李瓶儿的厚道,还有美食的味道,以及市面上一个猪头多少钱。多有意思。

再比如第25回,吴月娘带妻妾们打秋千。吴月娘是以处女之身嫁给西门庆的,其他全都是再嫁的寡妇或妓女。吴月娘的姿色、智商都不如别人,但她为自己的清白之身自豪,这是她隐形的道德优越感。虽然她不说,但伟大的作家用细节帮她说。潘金莲她们玩嗨了,笑得厉害,吴月娘就讲了一个故事:打秋千时不要笑,我在家里做女儿的时候,隔壁邻居家的周小姐就是打秋千时笑得厉害了,没坐稳掉下来,抓了喜。后来嫁人,人家发现她不是处女,把她休了。这只能是吴月娘讲的故事,有她的心思。打秋千不仅仅是打秋千,吴月娘把西门庆的女婿陈敬济请来,帮忙推秋千。张竹坡就说,吴月娘居然让一个男人来推秋千,这家风不行,祸事由此而起啊。陈敬济把李瓶儿裙子掀起来,露出她的大红底衣,推她的秋千……你看,陈敬济对小妾们的垂涎之心一下就出来了。在这里埋下一个伏笔,西门庆死后,陈敬济就成了后二十回的主角,把西门家搅得乱七八糟。

刚才说的是细节体现人性和性格,还有一种“细”是结构上的“细”。《金瓶梅》里有一个永福寺,在第一回就出现了,其实没什么作用,只不过是西门庆要结拜十兄弟,有人建议去永福寺,西门庆说寺庙不管这些事,去玉皇庙吧。而正是在永福寺,西门庆遇到了胡僧,得到了胡僧药(春药),这是他走向死亡的重要节点。此外,潘金莲死后被春梅葬在了永福寺后的白杨林里。在第100回末尾,正是在永福寺,吴月娘遇见了普静禅师,普静禅师把吴月娘和西门庆的儿子孝哥渡化出了家。也是在永福寺里,普静禅师为死去的人念了转生咒,让他们一一转世。这个结构是很精妙的。

《金瓶梅》插图

还有害死官哥的那只猫,也不是突然就出现的,而是一再做了铺垫,一切都水到渠成。我们都说《红楼梦》手法高明,“草蛇灰线,伏脉千里”,其实是跟《金瓶梅》学的。

界面文化:你在书中提到,《金瓶梅》是暗黑系的、无神的世界,亲情、爱情、友情都指望不了,遍地都是金钱、权力和性。这一点要如何理解?另一方面,好像不少评论人士认为《金瓶梅》是有佛教思想贯穿其中的。

刘晓蕾:这两个问题是有关联的。这一句话看上去很绝望,其实“暗黑系,无神的世界,亲情、爱情、友情都指望不了”不是指向“绝望”,而是想呈现一个事实。

第一,作者穿透世相,拒绝抒情,直接看到了人心、道德和世情的“空”,这跟作者的佛教思想有关,待会儿再说。

第二,“无神的世界”正是现代社会的一个写照,这是《作为欲望号的金瓶梅》这本书跟其他很多研究不一样的地方。很多人谈到《金瓶梅》会说这本书很深刻,但由于过于颠覆传统,过于黑暗冷酷,有点让人绝望。《金瓶梅》写的是商业社会和城市空间,而商业和城市是现代社会的特征,虽然在明代中后期只是阶段性的“现代”。《金瓶梅》里没有一个是种地的,连《红楼梦》写贵族还要有一个刘姥姥,有乌进孝,但《金瓶梅》全民皆商。商业和城市给了作者跟传统断裂的机会和勇气。城市是“陌生人社会”,把我们连根拔起,这也是现代社会的写照。现代社会本身就是“祛魅”的社会,尼采说上帝被杀死了,有一句话是“一切坚固的都烟消云散了”,这就是现代人和现代社会的“处境”,一切都变得不那么确定了,亲情、友情和爱情也很难指望。我们越现代,越会觉得都要靠自己。虽然让人感到很绝望,但人类对自己的处境会有更加全面的了解。长大肯定是要阵痛的,是很难过的。从这个角度来看《金瓶梅》里的人,比如应伯爵,你会有不一样的看法,你会对他们有更深的理解,而不是一味的批判。

《作为欲望号的金瓶梅》
刘晓蕾 著
生活·读书·新知三联书店 2021-05

接着说《金瓶梅》里的佛教思想。作者能够写出这样一个崭新的世界,毫不留情地颠覆传统的道德秩序和价值体系,有一个重要的根源在于他对佛教思想的借用。

《金瓶梅》里的佛教人士分两类,一类是王姑子薛姑子这种尼姑,是专门赚钱的,是世俗化的民间宗教。《红楼梦》的马道婆也是类似的人物,在明清小说里,民间宗教常常是被嘲笑挖苦的对象,那些尼姑、和尚、道士个个利欲熏心。但嘲笑归嘲笑,很多文人对佛教的义理还是尊重的。

《金瓶梅》的作者就是这样。黄道士给死去的李瓶儿念经,说的一长篇话,句句饱含深意,意指世人个个深陷欲望的深渊,贪生怕死,这其实就是佛教的义理。佛教对欲望的态度是“众生皆苦”,贪嗔痴这些欲望就是痛苦的根源等等。所以,作者一方面写他们的欲望,西门庆如何升官发财找女人,潘金莲和李瓶儿如何情欲满满,西门庆是“贪”,潘金莲是“嗔”,李瓶儿就是“痴”——贪嗔痴全了,这完全可以从佛教义理来解释。另一方面,《金瓶梅》又不是一部佛教书。作者把人间欲望写得热气腾腾,活色生香,如果体会不到“贪嗔痴”的佛教用意,很容易想歪,以为是在诲淫诲盗。

最后,在《金瓶梅》里,佛教思想不仅是结构上的需要,同时也有思想上的深度和厚度。作者在写热闹繁华的人间图景时,尤其是前面80回,西门庆一路爬坡,抵达人生顶峰,却总是在繁华背后透出“冰冷”的信息,所以张竹坡说作者善用“冷热金针”之法,繁华和凋败、生与死经常同时出现。比如第42-46回,作者描写元宵节的盛况,最后却来一句“总然费却万般心,只落得火灭烟消成煨烬”。冷冷一笔,真是透心凉。这种冷热交织的手法,后来《红楼梦》也学了去。这就是佛教的义理,即使现在繁华,但要知道这背后是一种空性,是不持久,大家都是因缘聚合的产物。

当然,作者知道自己笔下的这些人不会反思、不会觉悟,世间又有多少人能够反思和觉悟呢?但作者写这样一本书,写这么一群不觉悟的人,其实是想让我们觉悟的。至于我们觉悟不觉悟,就看我们自己了。

《醉里挑灯看红楼》
刘晓蕾 著
生活·读书·新知三联书店 2019-6

03 兰陵笑笑生和曹雪芹都是“超性别”的作家

界面文化:你怎么看待今天很多读者对文学作品的“三观审查”?

刘晓蕾:小说根本不能用道德或法律来约束,小说就是写人、写人性的,人性是一个非常辽阔的空间。“不道德的人”“不对劲的人”在文学里是有一席之地的,如果用三观来审查,那绝大多数世界文学名著都经受不了审查。比如陀思妥耶夫斯基的所有小说,托尔斯泰的《安娜·卡列尼娜》,福楼拜的《包法利夫人》,纳博科夫的《洛丽塔》,统统都得下架。

界面文化:《三国演义》《水浒传》里面女性都是集体失语的状态,但你看到《金瓶梅》却很懂女性。田晓菲和格非都提到过,西门庆结交十兄弟是对《三国演义》《水浒传》里“兄弟情义”、对男性同性欲望的反写和嘲讽,书里真正存在友谊的却是两个女性——潘金莲和春梅。从这个意义上,《金瓶梅》能不能说是女性主义的小说?

刘晓蕾:《金瓶梅》确实有这样的现象。但到底是不是女性主义小说,我持谨慎态度。从性别的角度读小说,自然有意义,但对《金瓶梅》这部小说来说,性别角度只是其中一个角度,而且是不太重要的一个角度。

讽刺兄弟情义,是因为兄弟情属于传统道德,这是对传统道德的态度,而不只是对男性的态度。男性的文化构成了传统社会的主流文化,所以反主流看起来像反男性。

兰陵笑笑生是一个男性作家,他对女性心理相当了解,写潘金莲和春梅的姐妹情谊,我们也能看见女性内心的纠结、痛苦和愤怒。但他写男人一样深刻又复杂,西门庆和应伯爵就被写得前无古人后无来者,我更愿意把他看成是“超性别”的作家。他和曹雪芹一样,都是伍尔夫说的那种“雌雄同体,具有伟大灵魂”的作家。

界面文化:你认为,从《水浒传》到《金瓶梅》再到《红楼梦》,人性是不断向上的。武松是丛林社会,西门庆代表欲望,贾宝玉带给我们的是爱和温柔。这样看来《水浒传》的文学水平应该是最低的吗?民间一直有“少不读《水浒》”的说法,你认为领悟作品有年龄的限制吗?

刘晓蕾:倒也不是这个意思。《水浒传》写的是人性的破坏力,这是人性原始的部分,是人性的一个方面。水浒社会是不正常的社会 ;《金瓶梅》里的人性更饱满更复杂,饮食男女这样的基本需求是被承认的。从这个角度来说,金瓶世界是比较正常的,当然精神的维度太弱了;而《红楼梦》里的人性更诗意、更高贵,活得更有尊严,更富有精神性,这其实是我们应该拥有的人生和生活。这三个方面加起来就是全部人性。

至于对《水浒传》的评价,我现在越来越谨慎了,不轻易言其好坏优劣。这本书写得很精彩,你看作者写林冲是怎样一步步被逼上梁山,把林冲的忍无可忍,只能再忍,再忍就得死,只好上梁山……这个过程写得多好。不过,《水浒传》只看见这些所谓英雄好汉,关注非凡人生,却看不见女性,也看不见平民百姓,所以我说它是“剑走偏锋”的小说,深刻但不博大。

“少不读水浒”还是有道理的。其实,《水浒传》比《金瓶梅》暗黑得多。一言不合拔刀相向,根本不会讲理,人就被杀了,在这样的社会里,普通人是很难活下去的。《水浒传》里劫法场的时候,李逵可是连围观群众也杀了不少。在《金瓶梅》里,这些普通老百姓能活下去,理发的、裁缝和货郎都活得好好的。

《金瓶梅》插图

界面文化:你觉得《水浒传》比《金瓶梅》暗黑,但是很多人都觉得里面是兄弟义气。

刘晓蕾:如果《水浒传》里有兄弟义气,也是小圈子的利益,跟社会正义无关。你看,宋江倒是义薄云天,可他带着兄弟招安讨方腊,兄弟们最后几乎都死了。梁山上的108将有多少是被“赚上山”的?是被“传销”上来的?就因梁山需要他们,需要徐宁秦明卢俊义,就把人家弄得家破人亡。这是兄弟情深?利益联盟而已。

还有,武松为了施恩,醉打蒋门神,他的正义也经不起推敲,如果蒋门神给他好酒好肉,他也会为了蒋门神打施恩的。施恩和蒋门神只是黑吃黑,没有谁更正义。

《水浒人物图卷》 清代 图片来源:图虫

04 《儒林外史》和张爱玲也深受《金瓶梅》影响

界面文化:在《秋水堂论金瓶梅》里,田晓菲认为《金瓶梅》更好,是因为《金瓶梅》看社会各阶层的各色人等更加全面而深刻,更严厉也更慈悲。比如说,《红楼梦》对赵姨娘、贾琏、贾芹这样的人物已经没有什么耐心与同情,就更无论等而下之的,《红楼梦》所最为用心的地方只是宝玉和他眼中的一班“头一等”女孩儿。你同意这个说法吗?

刘晓蕾:我个人很喜欢田晓菲解读《金瓶梅》,但唯独这一点我不太同意。《红楼梦》的灵魂是大观园,是贾宝玉和一群清净洁白的女儿们,是“人如何诗意地栖居”。它的主题变了,所关心的问题变了。像赵姨娘、贾琏、贾芹这些人,是 《金瓶梅》所关注的,但在《红楼梦》里,他们必然是配角。但对这些配角,也不是缺乏慈悲,我们依然可以从只言片语里,拼凑出他们的人生,看见他们的不得已。赵姨娘就和马道婆说,哪里有什么整块的绸缎到我的手里来?我们也可以从探春的痛苦,从贾环的处境,可以看出赵姨娘可恶之外的可怜。

贾琏也有可爱温情的一面。贾赦看上了石呆子的扇子,贾琏没买成,贾雨村把石呆子弄到狱里去,把扇子夺来送给贾赦。贾琏说,为把扇子把人家搞得坑家败业,不算什么能为。这句话是有良知的。

还有贾芹也有故事,有骑着大叫驴光擦的时候,也有被贾珍训得满脸通红的时候。

但这些人不是《红楼梦》的主角。《红楼梦》的主题跟《金瓶梅》不同。

界面文化:格非在 《雪隐鹭鸶:<金瓶梅>的声色与虚无》里认为,《红楼梦》是《金瓶梅》的“倒影”。  就是看到两者之间思想文化方面的关系,也看到《红楼梦》对《金瓶梅》的重要改造和超越。

刘晓蕾:这说得蛮精彩的。我再补充一句,在《金瓶梅》结束的地方,《红楼梦》才开始。《金瓶梅》的结尾有一段奇特的爱情故事,作者本来就看破人心世情,打碎传统道德和价值,却在最后两回写了韩爱姐很热烈地爱上一个人,一个浪子败家子陈敬济,这是人性废墟上开出的花,也是暗夜里的光。我认为,作者对人性还有期待,是绝处逢生,这是一种深刻的爱与慈悲。好在,在《红楼梦》里我们又看到了高贵纯粹深情的爱。

《金瓶梅》插图

界面文化:曹雪芹之后,还有没有哪些重要作家受《金瓶梅》影响比较深?能否请你讲解一二?

刘晓蕾:《红楼梦》很受《金瓶梅》的影响。此外还有《醒世姻缘传》《儒林外史》等。说句夸张的话,《金瓶梅》影响了太多的小说。毕竟它是第一部写日常生活(鲁迅说的世情小说),第一部文人独立创作……《金瓶梅》对《红楼梦》的影响是全方位的,我在书中有详细说明。

对《儒林外史》的影响是白描式的“讽刺”。《金瓶梅》也很会揶揄文人的:第49回,蔡御史来西门庆家里,西门庆给他安排了两个妓女。蔡御史一看,“欲进不能,欲退不舍”。西门庆就说,当年谢安也曾经有过这样的雅兴,蔡御史说我比不了谢安,但是你有王右军(王羲之)的高致啊。这种场合,谢安和王羲之的棺材板都会压不住的。但这种讽刺也不是一味刻薄,讽刺是很难写好的,一不小心就流向“冷嘲”,但《金瓶梅》的作者能原谅他们。

还有张爱玲也深受《金瓶梅》的影响。我在网络上有一门课《刘晓蕾讲透金瓶梅》,有一节课专门讲张爱玲和《金瓶梅》的关系。张爱玲曾经说,《金瓶梅》和《红楼梦》是她“一切的源泉”,很多人都注意到《红楼梦》的影响,其实从她小说的内容和精神气质以及她的个人生活而言,她和《金瓶梅》关系更近。

Viewing all 11848 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>