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

一篇文章看懂怎么用iPhone当交通卡

$
0
0

iPhone终于接入北京、上海两地公交系统,如果你的iPhone还没开通公交卡,请参考《 iPhone秒变交通卡 上海Apple Pay公交支付全攻略》一文。在潇洒刷手机前,你或许还心存疑虑,我们以自己实际使用体验来回答大家最关心的问题。

新过闸口

1、 哪些设备可以用?

答:理论上拥有NFC、支持Apple Pay、能升级到iOS 11.3和watchOS 4.3以上版本的手机手表都可以使用。

手机包括:iPhone SE,iPhone 6,iPhone 6 Plus,iPhone 6s, iPhone 6s Plus,iPhone 7,iPhone 7 Plus,iPhone 8, iPhone 8 Plus,iPhone X。

_1065306

手表除第一代Apple Watch外,Apple Watch Series 1、Series 2、Series 3和同代的运动款,爱马仕版,Edition陶瓷板等都可使用。

_1065302

iPad全系都不行!

2、那我是国外带回来的iPhone能用么?

答:也可以用,绝大部分海外版本的iPhone只要区域切换成中国,都能使用交通卡功能。

3、哪里可以使用快捷交通卡?

答:上海公交、地铁、轮渡和磁悬浮均可使用。出租车受读卡器改造速度限制,无法保证100%双出,但上海大型出租车公司的新车基本都能用。

_1065286

4、Apple Watch怎么变身交通卡?

答:首先需要在iPhone上开卡成功,升级到watchOS 4.3后,打开Watch App,在“钱包与Apple Pay”中“手机上现有其他卡片处”点击“添加‘’,即可将交通卡从iPhone转移到Apple Watch。

5、“转移?”

答:是的,手表手机无法共用一张交通卡。进入Watch App后,选择“钱包与Apple Pay”,点击“上海公共交通卡”并拖动到最下方,可以将卡片添加回手机中。

微信图片_20180330163528

6、那…有没有优惠?

答:目前没有额外优惠,但使用iPhone乘车享受和实体交通一样的换乘优惠,后续苹果可能会有补贴和促销活动。需要注意的是,目前在上海使用“Metro大都会”App,扫二维码坐地铁每天前两笔有额外的9折优惠,但扫码距离可能同时触发Apple Pay交通卡,造成重复扣费。

7、听说还有“吸星大法”?

答:在三星手机中有北京交通卡的用户,可以iPhone中添加实体卡并输入的卡号,随后NFC接触完成交通卡余额的转移。但iPhone对小米手机中上海交通卡的目前卡号能转移,但余额无法转移。目前,暂时只能从其他手机中将交通卡和余额转移到iPhone,其他厂商后续也可能上线此功能。

8、能否用信用卡充值?

答:在苹果自带的钱包与Apple Pay中无法直接用信用卡充值,但可以使用京东闪付,在京东闪付的付费顺序中设置信用卡优先即可。使用“上海交通卡”App则支持Apple Pay中绑定的信用卡,也可以使用微信、支付宝等第三方支付。

9、iPhone充当公交卡使用的是什么技术?

答:目前在国内实现公交卡电子支付,NFC SIM、各种NFC手环,所有能付公交卡的手机,都由复旦微电子集团NFCOS提供后台支持。截止今天下午5点,上海、北京的NFC搭乘的数量大幅上升。除了Apple Pay,Samsung PAY、华为、小米的新开卡数量和使用量也有显著增长。

10、使用是否方便?

答:和实体交通卡一样,所有的地铁闸机口都能使用。靠近刷卡机后手机屏幕自动点亮,刷卡成功。只要手机有电,无需联网、无需解锁或打开Apple Pay,响应速度和实体交通卡一致。

_1065256

11、那手机丢了岂不危险?

答:是的,好在交通卡扣费只扣充值余额。手机或手表丢失后请第一时间打开苹果官网,登陆个人Apple ID,在设备中将支付移除。

TIM图片20180330151144

TIM图片20180330151208

12、能否退款?

答:可以,需要通过“上海交通卡”App来申请退卡,卡内余额和押金均可退还。


人最大的教养,就是和颜悦色

$
0
0



来源:京博国学(ID:jingboguoxue)

和颜悦色是教养,亦是一种深情。



俗话讲,“脾气人人有,拿出来是本能,压下去才是本事。”胡适先生也曾说过:“世间最可恶的事,莫如一张生气的脸。”


待人和颜悦色,不仅是一种美德,更是一个人最大的教养。


 

1.对陌生人和颜悦色,是礼


古书有言:“天地之气,暖则生,寒则杀,性气清冷者,受享亦凉薄,唯和气热心之人,其福亦厚,其泽亦长。”


你对待别人的态度,就是将来别人对待你的态度,唯有和颜悦色宽待他人,才有可能得到热情的回应。


在知乎上曾有这样一个问题:“为什么了解一个人要看他对陌生人的态度?”


其中有一个答案令人印象深刻:“因为陌生人和你的利益不相关,对利益相关者的态度取决于智商和情商,对不相关者的态度取决于素质和修养。”


看清一个人的人品和教养,就去看看他们如何对待陌生人。


不管是服务员还是农民工,凡是有受到过良好教养的,必定会懂得去尊重他人。


有两则新闻,看完让人心生感悟:


公交车刚到站,一名穿着讲究的女士,和一位身上带泥的工人大叔一起上车,女士为了占位置,车刚停稳就匆匆往里抢,撞到了大叔还不打紧,可她一点歉意都没有,还不友善的翻着白眼讽刺着:“农民工还坐车,衣服这么脏,能不能注意点。”


大叔特别不好意思,讪讪的低下头,也没在一旁的空位坐下,直接站在车门旁,也没有作声。


而在另一个城市,由于突降大雨,导致交通堵塞。一名交警仍冒雨执勤,一位女司机主动下车,将一把绛红色大伞撑到交警头上,为其挡雨。


事后了解,这名女司机与交警并不相识,女司机却足足为这个陌生交警撑了五分钟的雨伞,直到交通恢复畅通,才留下雨伞,低调开车离开。


什么是教养?就是能站在对方的角度去思考问题,懂得每个人都不容易,对待陌生人不是干瘪单薄的客套,而是推己及人的和颜悦色,这就是你的教养。

 

 

2.对父母和颜悦色,是孝


 

在一次访谈中,杨澜曾问周国平:“为什么我们都把好脾气留给外人,却把坏脾气留给最爱的人?”


连这位一向儒雅的哲学家也说:“这个错误,我也常常犯。”


周国平还说: “对亲近的人挑剔是本能,但克服本能,做到对亲近的人不挑剔是种教养。”


生活中,我们和不同的人相处,会展现不同的态度:陌生人前是规矩礼貌,疏离中带着客气;同事之间可以开几句熟络玩笑,但始终不失分寸;普通朋友嘘寒问暖,亲近但不亲密;在亲近的人,尤其是父母面前本性却完全暴露无遗。


孔子讲,孝敬父母最难的事情是“色难”,就是说最难的是给父母好脸色。


给父母买好房子、请保姆、吃大餐、去旅游是物质上给父母的享用,这是低层面的“孝”。


而高层面的“孝”,应该表现为对父母精神上的敬重和感情上的安慰。所以,对父母能做到和颜悦色,也是最大的教养。


著名作家史铁生双腿瘫痪后,脾气变得喜怒无常,经常对母亲发脾气。然而母亲即使身患肝病,口吐鲜血,心里口里记挂着的还是自己的儿子。


后来母亲死了,史铁生才突然醒悟:“这倔强只留给我痛悔,丝毫也没有骄傲。我真想告诫所有孩子,千万不要跟母亲来这套倔强,我已经懂了,可我已经来不及了。”


“色难”难在何处?难在很难有一颗恭敬的心,难在没有一个谦和的态度。


我们好像变得很厉害,动不动就把父母当佣人一样使唤,稍微有不顺心就对父母一通发泄,从来不给他们好脸色看。


我们不经意的态度,往往伤害他们最深。所以“色悦”成了衡量一个人孝心的道德标尺。


真心爱父母,应该和颜悦色,从内心深处发出微笑,让他们感到快乐、幸福。


父母在,人生尚有来处;父母去,人生仅剩归途。


 

3.对爱人和颜悦色,是爱

 

爱人,是这个世界上,虽然没有血缘关系,却要相伴最久的人。对爱人的态度,藏着一个人最真实的教养。


几年前有部名叫《不要和陌生人说话》的大热电视剧。


男主角安嘉禾有体面的工作,洁净的外表,温和的言谈。工作上救死扶伤,滴水不漏;为人谦卑有礼,无懈可击。在外人看来,他不仅懂礼,而且守节,几乎是个一等一的好男人。


但是,当他站在爱人梅湘男面前,他的暴戾、粗鄙、狰狞、恐怖、歇斯底里全部暴露,他变成了恶魔,变成了人渣,变成了暴徒,变成了罪犯,变成了虐待狂。


他寻找各种借口,对自己的妻子施暴,打得她奄奄一息,双腿残疾,人生无望。


安嘉禾算是个有教养的人吗?如果说教养就是一个人骨子里的和颜悦色,那么,100分的教养试卷,他能得负100分。


很多时候,人在外面受了委屈或承受一些压力,没有办法发泄出来,只好对亲密的人发泄。


的确,爱人是跟自己关系最亲密的人。但关系亲密并不意味着能无止境地无理取闹,没有人天生就该承担他人的情绪发泄。


胡适的妻子江冬秀是出了名的“母老虎”,脾气极大。


每次江冬秀发脾气,大喊大叫时,胡适就躲到厕所里,借口要漱口,故意把牙刷搁进口杯里,把声音弄得很响。如此这般,避免正面冲突,让彼此好受。


胡适曾在《我的母亲》里提到:“世间最厌恶的事莫如一张生气的脸;世间最下流的事莫如把生气的脸摆给旁人看。这比打骂还难受。”他说到做到,从不给妻子一张生气的脸。


其实,和颜悦色,是深爱的外在表现。真正有教养的人,是把好的情绪和态度留给爱人。


一辈子那么短,我们总该择一个心里有暖意的人相处,彼此温柔相待。


 


作者简介: 京博国学,来源:京博国学(ID:jingboguoxue),本文经授权转载。


中考即将来临,作文成绩还能在提高一下吗?

邀请全国中考作文押题名师

中学语文高级教师——刘泳美

浓缩21年的作文教学经验,

 

带给考生们实效的考场写作技法指导。






 

Java 堆内存溢出梗概分析

$
0
0
引用
原文:Java Out of Memory Heap Analysis
链接: https://dzone.com/articles/java-out-of-memory-heap-analysis
译者:dreamanzhao, 无若

任何使用过基于 Java 的企业级后端应用的软件开发者都会遇到过这种低劣、奇怪的报错,这些报错来自于用户或是测试工程师: java.lang.OutOfMemoryError:Java heap space。

为了弄清楚问题,我们必须返回到算法复杂性的计算机科学基础,尤其是“空间”复杂性。如果我们回忆,每一个应用都有一个最坏情况特征。具体来说,在存储维度方面,超过推荐的存储将会被分配到应用程序上,这是不可预测但尖锐的问题。这导致了堆内存的过度使用,因此出现了"内存不够"的情况。

这种特定情况最糟糕的部分是应用程序不能修复,并且将崩溃。任何重启应用的尝试 - 甚至使用最大内存(-Xmx option)- 都不是长久之计。如果不明白什么导致了堆使用的膨胀或突出,内存使用稳定性(即应用稳定性)就不能保障。于是,什么才是更有效的理解关于内存的编程问题的途径?当内存溢出时,明白应用程序的内存堆和分布情况才能回答这个问题。

在这一前提下,我们将聚焦以下方面:
  • 当内存溢出时,获取到 Java 进程中的堆转储。
  • 明白应用程序正在遭遇的内存问题的类型。
  • 使用一个堆分析器,可以使用 Eclipse MAT 这个优秀的开源项目来分析内存溢出的问题。
配置应用,为堆分析做准备

任何像内存溢出这种非确定性的、时有时无的问题对于事后的分析都是一个挑战。所以,最好的处理内存溢出的方法是让 JVM 虚拟机转储一份 JVM 虚拟机内存状态的堆文件。
Sun HotSpot JVM 有一种方法可以引导 JVM 转储内存溢出时的堆状态到一个文件中。其标准格式为 .hprof 。所以,为了实现这种操作,向 JVM 启动项中添加 XX:+HeapDumpOnOutOfMemoryError 。因为内存溢出可能经过很长一段时间才会发生,向生产系统增加这一选项也是必须的。
如果堆转储 .hprof 文件必须被写在一个特定的文件系统位置,那么就添加目录途径到 XX:HeapDumpPath 。只需确保该应用对于指定目录途径始终拥有写入权限。

原因分析

101:了解内存溢出错误的本质

当尝试去评估和了解一个内存溢出错误时,最先做的事情应该是观察内存增长特征。根据情况做出可能性的评估:
  • 尖峰状:这种类型的内存溢出在某种类型的加载上会是比较激烈的。当 JVM 分配内存给 20 个用户时,应用程序可以正常运行。但是,如果到第 100 个用户时可能会遭遇到内存峰值,从而导致内存溢出。有两种可能的办法去解决这个问题。
  • 泄露:由于某些编程问题,内存使用随着时间的推移逐渐增加。

拥有良性垃圾回收机制的健康图表
 

健康一段时间后,随时间推移而泄露的图表
       

引起内存使用凸起、导致内存溢出的内存图表

在我们了解导致使用率激增的内存问题的本质之后,基于从对分析中得到的推断,下面的这些方法或许可以用来避免遭遇内存溢出的错误。

解决内存问题

  • 修复引起内存溢出的代码:由于应用在某段时间内增量添加了一个对象而没有清除其引用(来自正在运行的应用程序的对象引用),导致不得不修复程序错误。例如,这一错误可能是插入了一个哈希表, 其中的业务对象会逐渐增加,然而业务逻辑和事务在完成之后并没有删除这些对象。
  • 增加内存最大值作为一种修复方法。在了解了运行内存特征和堆之后,可能必须增加分配的最大堆内存来避免再次发生内存溢出,因为推荐的最大内存值不能够满足应用程序的稳定性。所以,应用程序可能不得不基于堆分析器的评估,将 Java -Xmx 的 flag 信息更新成一个更高值后再来运行。
堆分析

下面我们将详细分析如何使用一个堆分析工具来分析堆转储。在示例中,将使用到 Eclipse 基金会的开源工具 MAT 。

使用 MAT 进行堆分析

是时候进行深入探讨了。我们将通过一系列的步骤,帮助探索在 MAT 中的不同表现和视图,以获取一个堆内存溢出的示例并思考分析。
1. 打开内存溢出错误发生时产生的 .hprof 堆文件。确保复制转储文件到一个专门的文件夹下,因为 MAT 会创建许多索引文件:文件 -> 打开
2. 打开转储文件,有内存泄漏嫌疑报告和组件报告的选项。选择运行泄漏嫌疑报告。

3. 泄漏嫌疑表打开后,在预览窗口的饼状图会展示在每个对象基础上保留内存的分布情况。它显示了内存中的最大对象(拥有最高保留内存的对象 —— 累积的内存和引用的对象)。
4. 上面的饼图通过聚合拥有最高内存引用(本身内存和总内存)的对象来展示 3 个问题嫌疑人。
让我们逐一分情况查看,评估它是否是内存溢出错误的根本原因。

可疑点 1

由 “<system class loader>” 加载的 454,570 个 “java.lang.ref.Finalizer” 实例占用了 790,205,576(47.96%)个字节。
这就是告诉我们有 454,570 个 JVM finalizer(终结器)实例占据了分配的应用内存的近 50 %。
假设读者知道 Java Finalizer 是做什么的,上面的信息会让我们明白什么呢?
入门阅读: http://stackoverflow.com/questions/2860121/why-do-finalizers-have-a-severe-performance-penalty
本质上,开发者编写了一些定制化的终结器去释放一个实例的资源。这些由终结器收集的实例不在 JVM 使用单独队列的垃圾回收算法的范围之内。实际上,这种途径比起垃圾回收机制的清理路径更长。所以现在我们应该努力搞清楚这些终结器到底终结了什么?
也或许是可疑点 2 ,占据了 20% 的 sun.security.ssl.SSLSocketImpl 。我们能确认是否这些就是要被终结器终结的实例吗?

可疑点 2

现在,让我们打开在 MAT 顶部的工具按钮下面的 Dominator 视图。我们会看到所有的列出的类实例,经由 MAT 解析展示出有效的堆存储。

下一步,在 Dominator 视图,我们尝试理解 java.lang.Finalizer 和 sun.security.ssl.SSLSocketImpl 之间的关系。我们右键点击 sun.security.ssl.SSLSocketImpl 这一列,打开 GC Roots  -> exclude soft/weak references。

现在,MAT 将会开始绘制内存的图表来显示 GC root 的路径以及它所对应的实例引用。这会被显示在另外一个页面上,显示的引用如下:

如上面引用链显示,实例 SSLSocketImpl 来自于 java.lang.ref.Finalizer,整个 SSLSocketImpl 实例大约占用了 88k。我们还注意到 finalizer 链是一个针链表数据结构它指向下一个实例。
推论:在这一点上,我们有一个明确的感觉,Java finalizer 试图在收集 SSLSocketImpl 对象。为了解释为什么还有很多信息没有被收集到,我开始检查代码。

检查代码

代码检查需要查看是不是由 socket 套接字被关闭导致的。在这种情况下,它显示与 I/O 相关的所有流,需要被正确地关闭。在一点上,我们怀疑 JVM 是始作俑者。实际上,在 Open JDK 6.0.XX 的 GC(垃圾收集器)上的代码中有一个 BUG。
我希望这篇文章给你一个模式来分析 Java 应用中的错误是由堆存储还是内部问题导致的。希望你使用堆分析愉快!

扩展阅读

Shallow heap (浅堆) vs. Retained Heap (保留堆)
浅堆是一个对象消耗的内存。根据情况,一个对象需要 32 位或 64 位(取决于其操作系统架构),对于整型为 4 字节,对于 Long 型为 8 字节等等。依据堆转储格式,其内存大小(比如,向 8 对齐)或许适应于更好地塑造虚拟机的真实消耗。
X 的保留集合是当 X 被垃圾回收时,那些将要被移除的对象集合。
X 的保留堆是在 X 的保留集合中所有对象的浅堆之和,也就是 X 存留的内存。
总体讲,一个对象的浅堆就是其在堆中的大小。同一个对象的保留大小就是当对象被垃圾回收时堆内存的总量。
一些对象的主要集合,比如某一特定类的所有对象、或是由某一特定类加载器加载的所有类的所有对象、或仅仅是一些任意的对象,它们的保留集是如果那些主要集的所有对象变得不可接近时所释放的对象集。
保留集包括这些对象和仅通过这些对象才能获取的其它对象。保留集的大小是包含在保留集中的所有对象的堆的大小。

感谢 jihong10102006投递这篇资讯

资讯来源: 开源中国

已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



王兴:美团要成为能够“购买服务”的亚马逊|界面新闻 · 科技

$
0
0

3月27日,美团网创始人兼CEO王兴接受了硅谷科技新闻媒体The Information的采访,讲述了美团的一些往事和对未来的规划。

2010年,王兴创办了美团网,至今已有八年。最初,美团的投资方包括红杉资本和阿里巴巴,后者还参与了公司后续几轮融资,在美团早期发展过程中起到了关键作用。

2015年10月,美团与大众点评正式宣布合并,公司估值由70亿美元提高到180亿美元,而大众点评的后盾是腾讯。那时,美团就已经和阿里巴巴分道扬镳了。王兴表示,这主要是因为阿里希望能够获得更多控制权,但王兴希望美团能够成为一家独立的公司。

如今,美团已经成为了估值达到300亿美元的线上服务平台。据彭博社援引知情人士消息称,美团近期正在讨论最早于2018年年内在香港IPO,估值600亿美元。

王兴表示,自己在公司占有的股份略微超过10%。以此计算,如果公司成功IPO,那他的个人资产将会达到80亿美元(按照800亿的估值计算)。王兴还表示,由于始终没有出售手中的股份,他只能找父母借钱来补贴家用。

目前,美团的业务已经涉及到外卖、电影票、旅游等多个领域,覆盖了超过3亿国内用户。

“虽然我们看起来像是在发展很多不同的业务,但实际上只是朝着一个目标在努力。”王兴说道。“仔细观察所有垂直领域后,你会发现他们总会在某个用户群体形成交集;而就餐、点餐、看电影、旅游、租车的用户,基本上就是同一群人。”

过去一年,共计3.2亿用户在美团上进行过至少一次消费。美团方面表示,大约90%的用户流量都是来自于自己的APP,这同时大大降低了用户尝试新服务的成本。

但王兴认为这远远不够。美团的核心业务是食品,每天会产生2000万单外卖服务,这几乎占据了整个美团一半的业务量。不过,“单就中国13亿人口来看,大部分都是一日三餐,每天就应该有40亿顿饭。”他在接受采访时说道。

他相信,美团未来将会服务于中国6.5亿中产阶级人群,而智能手机在这群人中几乎全部普及。这是个雄伟的目标,国内能够达到这个规模的互联网企业也是少之又少。比如,微信最新公户的月活跃用户是10亿,阿里巴巴的月活跃用户为5.8亿。

“用户可以在亚马逊或淘宝上买到非常多东西,但这两者都只是用于购买实物的电商平台(e-commerce platforms for physical goods),而美团则是能够购买服务的电商平台(an e-commerce platform for services)。”他补充道,“哪种电商平台能够拥有上百万甚至数十亿的交易呢?”

王兴还提到,美团最大的成本来自于50万名送餐骑手。过去一年,他们送出了约70亿份外卖,所有配送路径都是通过算法计算得出的,从而保证每个订单的配送时间不超过28分钟,并且尽可能触及更多顾客。

与此同时,美团还专门成立了研究小组,致力于开发出能够送餐的智能机器人。王兴表示,这种送餐机器人能够在五年内投入使用。

“说实话,这仅仅是时间问题。”他说道。

看中国为什么不受发达国家待见——某美国芯片公司员工

$
0
0

作者:知乎@山有枝


作者:知乎@山有枝


我是偏乐观的。


首先声明我承认中国有很多问题。但我个人是不太相信那种把中国的各种问题一罗列,就得出结论迟早要完之类结论的。这种论证太廉价。要说问题,三四十年前问题更多,八十年代的公知讲喊的是“河殇”,但中国没有完蛋,还是走过来了。风物长宜放眼量。


看这个问题有很多角度。给大家提供一个我自己私人的一个角度。算是十几年参与中国制造业的一个体会。

我在一家美国集成电路公司X。虽然不涉及什么机密但我还是隐去公司名字,当然行内人一看也明白。无论是规模还是技术,说X在世界顶级之列应该没有争议。销售额X不是最大,Intel最大,X稳定在全球第三到第五左右。但X特点是产品线特别特别宽。宽到什么程度呢?如果按完整产品型号来细分:几万多种,比排名第二到第十加起来的总和还多。从几千美金一片的专用处理器,到中国花钱都买不到的禁运的高性能AD,到几角几分美金一片的小逻辑小运放芯片,X都有。


正因为这样的特点,X产品应用的领域非常非常广泛。基本上只要带电的地方,都可能用上X的产品(只是说可能而不是一定,毕竟X也面对很多竞争),甚至你眼前这个手机可能已经用上了。基站、服务器、手机、电脑、电视、数控机床、医疗器械、汽车、高铁、高压输电、智能穿戴、点钞机、POS机(扫二维码那种)、伺服、PLC、空调、机器人、工业控制、数控机床、变频器、电影、照明、新能源、无人机、电梯、冰箱、洗衣机、音响、示波器、声光电玩具、水电气表、摩拜的GPS电子锁……基本上你能想到带电的应用,或多或少都能用上X的产品。我罗列的这些应用,只要在中国能排进前几位的公司,肯定都是X的重点客户。行外人可能觉得不可思议,但X就是这么样的公司。


所以我自己观察一个东西:"X指数"--就是X在中国的总销售额。我觉得这个X指数能反应一定的问题,因为:


1. 如前面所说,X的产品很全,可以覆盖非常非常多行业。


2. 芯片是很多行业的源头或核心。很多产品都需要芯片,连运动鞋里都带芯片了。因此芯片是很多行业的指向标。很多行业要么直接是我们的客户,要么被我们的客户所间接覆盖(譬如纺织业被我们做电动缝纫机的客户所覆盖)。通过芯片可以见微知著。


3. X在中国的销售额规模已经很大,而且高度分散。快速增长到今天已经每年几百亿人民币,这个规模我认为已经有统计代表性了。而且因为产品种类多,X在国内的客户数以万计,高度分散。


4. 能用X产品的公司,或者说需要芯片的公司,需要一定的研发能力。虽然不一定是最高精尖的部分,但在制造业里也绝对脱离传统或低端了,不是钢筋水泥傻大黑粗,也不是衣服鞋子塑料盆。他们的产品可算中档工业品,少部分可算高档工业品。他们的表现一定程度反映了中国制造业的转型。


5. 还有一个很重要的:X的数据系统统计销售额,是把纯代工加工排除在外的。举个例子:富士康在中国生产苹果手机戴尔电脑,里面用到X的芯片。在X的体系里这个业绩是算在美国团队而不是中国的。因此这里说的X在中国的销售额,反映的是研发设计和生产都由本土客户产生的生意。行内话叫Local Demand Creation,本土需求。虽然富士康之类也是中国制造业的一部分,但本土需求显然含金量更高。


说了那么多,结论是什么呢?


1. 结果是按年看05年至16年的每年,都刷新前面的记录,创造了历史最高。包括08年金融危机那两年。


2. 12年还是13年,中国就成为X全球第二大市场了。超过日本,超过整个欧洲之和,台韩自然不在话下,整个印度大概还没有我们一个城市生意大。当然最大的还是美国(一家苹果就占了X全球生意的不小一块,也是最大的客户),但中美已经是一个等级,远超其它国家。如果按照宽口径统计中国制造业,就是把上面第5条所排除的代工需求算进去,中国早就超过美国了。


3.  这两年都说经济不太好,生意也没有想象的难做--17年2季度X指数又创新高。现在3季度过去两个半月,再刷新历史最高没有悬念。而且上半年增速还达到了近年少见的水平。几个规模类似的友商增速也都创近年最高。


4. X自己生意涨,但其实在中国市场可能是丢份额的。部分是输给了外资竞争对手,不少是丢给了国产。譬如华为的海思芯片就在IPNC等图像处理领域把我们的DSP干翻了。说明中国对芯片的消耗涨的可能更快。


本质上,没有下游巨大的研发、设计和制造能力,是不可能需要上游这么多芯片的。所以, 以我在X这么长时间观察中国制造业的理解,我们的制造业确实在扎扎实实的转型升级。中国现在靠的是海量的工程师红利(不光是IT电子类,也包括土木工程、化学生物等)。现在看耐克把工厂搬到东南亚就宣称中国要完的人,大概活在一二十年前。


很多国家,连X这个以触角长为特点的IC公司,甚至连个办事处都没有。但是X在中国,晶圆厂、封测厂、物流中心、做研发,更不要提市场、销售、技术支持。投资以数百亿计。从这个角度上说,我觉得中国的产业在一点点往上爬,已经和普通国家拉开差距。


产业、科技能不能往上爬,是国家能不能走出中等收入陷阱最重要的决定因素,甚至是推动上层社会生态政治生态的因素。除了那些资源型国家(如沙特),所有发达国家之所以发达的根本原因,就是在科技树、产业树上站得高。老牌发达国家从工业革命就开始爬了,后起如韩国虽然时间晚但在直追。普通农业、低端制造业不可能使国家富裕,那些行业不可能有超额利润。只有有技术含量的工作才能带来丰厚回报,这点对个人、对公司、对国家都是如此。


关于补充评论:


很多人质疑这个角度的代表性。我觉得:讨论中国经济,全面谁也不敢说。但数百亿规模、近百个季度的趋势、高度分散的下游应用和客户,总能反应点什么吧?更重要的:芯片是高端制造业的根基,对它需求直接反应了很多行业,是很多行业的指向标。 很多行业要么直接是消耗芯片的客户,要么被芯片客户所间接覆盖。


想知道现在中国制药企业怎么样?去看看那些卖光谱分析设备的客户买多少东西就知道了。想知道房地产怎么样?看看我们的芯片在电梯控制器客户里如何,看看空调客户业绩如何。想知道电影院线生意好不好,看做影院投影的买了多少数字微镜芯片--这个芯片拿过奥斯卡奖。


想知道国内自主汽车怎么样?看几个国内车厂要的汽车级芯片多不多。想预测下互联网巨头的生意?看看服务器上芯片要的多不多、数据中心专用的电源和温湿度传感芯片卖的如何。前些天大家看到消息说世界烟草销量跌了,你以为是因为控烟?那是因为电子烟…… 至于那些本来就是电子产品的行业,如手机电脑通信设备之类,更是不用说了。


所以大家可以理解为什么国家下大力气要搞定集成电路芯片。


201703补充


今年一季度X指数很好,不一定超过去年四季度,但同比增速应该是近年来一个高点。今年半导体业回暖应该是路人皆知的现象吧,知乎上都有人问。说明下游制造业很好。


201707补充


上半年国内所有大区和所有团队同比生意都非常好。全国年化几百亿的生意规模,还成长了百分之*十多。尤其是中小客户团队,就是专做长尾中小企业的部门(全国上万客户),也全部成长了百分之*十多,非常难得!


【讲个故事吧】


前东家大小产品线有几十条。以前有个产品线有一种芯片,xxx2046. 是个很简单的IC,就是电阻式触摸屏控制器。手机用的早的都知道,iPhone之前也有触屏手机,但那是电阻式触屏,体验远没有现在的电容式触摸屏好,还需要一个小笔点来点去。当年高档品牌多普达(后来的HTC)、三星、各种PDA、国产品牌等有很多款。


那时触屏手机不像现在那么100%流行,但也算是海量消费品了,作为一个生意来说量很大。我司那个IC卖多少钱呢?刚出来时候1美金一颗,每个手机就要一个,而且市占率极高,几乎垄断。


大家不要小看1美金,一般一个手机公司的年销量都是以百万千万计,也就是说这么个十几平方毫米的芯片上一个手机公司一年就要花数百万数千万美金。

做这个产品的老外不要太爽啊。就几个人,每次来中国就像是拯救世界似的,对国内品牌手机是看不上眼的,缺货时还涨涨价。欧洲那位七八月是肯定休假的,去客户那还总是鄙视加班---my value is family first.


后来呢?国产的这种IC出来,东西刚出来大概是我们80%的品质,70%的价格,也有人用,低端品牌。然后慢慢的,品质越来越好,价格越来越低。人家慢慢往上爬,往大做。我司反正利润高,跟着降价,九毛美金、八毛、七毛...就这样一路和国产的杀下去,你猜最后杀到多少? $0.22美金。完全同样的东西,以前卖$1,现在卖$0.22,还在卖,说明还是有钱赚。后来我司出了个改进型号,也没太复杂,就是加强了ESD防静电,加快了反应速度。新型号出来后市场价格大概稳定了大半年,后来国产的也跟进同等性能产品,价格迅速降到$0.2以下,我司觉得没意思,就不做了。那六七个人也不在这产品上了,有的换产品做,有的换了个产品线,有的换了公司。现在这种IC还是有,不过不用在手机上了,在只能用电阻屏的特殊场合,如一些工业、汽车等。现在这种触控IC大头都是国内的了。


我那时看着一个芯片从一块多杀到一毛多,都看傻了。2毛多我司都还有利润,再想想以前国产替代品没出来时赚的利润,更傻了。那时我开始隐约理解为什么欧美人能过得那么优雅了。


这只是我司一个型号上的小故事,我司产品有大几万个。

后来这种事也越见越多,类似的事情在客户那也越见越多---国产通信电源出来前,国际品牌卖上万,我们的客户做出来了,现在卖几百,还送一堆服务。进口变频器几万块,国产出来后卖几千。


那些老外以前下午五点就下班了,现在晚上还要陪着国内客户concall。利润降低算是好的,整个市场被端了那是要丢饭碗了。--关键是中国人还特别多,好多领域都想搞。不知道他们想起以前的奶酪,想起在深圳的日子,是否待见中国。


你抢了别人那么多饭碗,当然不可能受别人的欢迎,至少也是原因之一。君不见特朗普竞选,三句不离“中国人抢了我们的工作”。当年美国的排华法案,最大的推手就是美国的“无产阶级”--各个产业的蓝领工人,因为中国劳工吃苦耐劳抢了他们不少饭碗。

=========

有人误解我举的例子只是中国人做点低端的东西。首先,芯片分档次,但能做出芯片就不低端。对于发展中国家来说,再小的芯片也比做衣服鞋子塑料盆、或者卖矿卖石油高端多了。其次,低端不一定不赚钱。我司现在自己的理念是:把产品做的又便宜又够用是门有技术含量的手艺活。


大产品的例子也不少,如我司数字电视、IP camera的芯片早就被华为海思干翻了。还说手机,当年摩托诺记一统天下的时候,我司的手机主芯片差不多在全球每个角落,影响力大到公司CEO来华被386接见。现在早就从手机套片撤出了,倒是华为海思的手机套片这两年有数以亿计的销量。

===============

还有人说,日本人、韩国人也抢了很多高端的饭碗,为何他们没有那么不受“待见”?我想说:这么说的人肯定是小年轻,八九十年代日本和美国烽火连天的贸易战、汽车战、牛肉战大概没有什么印象了。


其次更重要的,中国和日本、韩国是完全不一样的国家。我是说规模。这个规模是质的不同。日本才1.3亿人口,韩国满打满算才5千万人口。中国是14亿。日本才能抢多少产业?韩国更不用提了。而中国的人口比所有发达国家总人口加起来还多。如果这么多人口可以加入工业化的大潮,不管你是用何种方式加入进去--富士康产线的小妹也好,京东的送货员也好,大疆的研发工程师也罢,天天跑企业的PE/VC也罢---如果这么多人在现代化的历史进程中发展起来、动员起来,大家觉得中国可以到什么水平?


中国的规模保证了:


  1. 中国人可以进入很多的领域:如果你只有5000万人口,你可能电子发达、造船发达,但是你机械工程、生物、IT、航天...就没有足够的工程师了。而中国不会,中国每个领域的潜在人力资源规模都差不多顶上一个中等发达国家。


2. 中国从产业链低端往上吃,但是即使往上爬,吃到嘴里的也不放口。日本、韩国他们的产业链升级,相对低端的就转移出去了,转移到中国、东南亚、印度。可中国有丰富的不同层次的资源,少数人少数产业往上走的同时,相当部分的金字塔的低端仍然吃在自己口里。中国现在机电制造发达,可还是有大量的来料加工企业、衣服鞋子塑料盆。富士康深圳呆不下了,可以去东莞、去河南。至少在相当长的时间之内,产业转移可以在中国内部完成。以前是日韩吃肉中国喝汤,等中国这么多人开始吃肉时,汤也没法剩给别人。这个是很恐怖的。




特朗普为何要对亚马逊“动手”?

$
0
0

钛媒体 TMTPost.com

|科技引领新经济|

美国总统特朗普近期要对亚马逊“动手”,而主要的原因是亚马逊作为电商企业缴税过低。事实真的如此简单吗?

钛媒体作者丨孙永杰

脉脉上的一则信息,让沉寂已久的阿里游戏又回到人们的视线当中。

据CNBC报道,美国总统特朗普近期要对亚马逊“动手”,而主要的原因是亚马逊作为电商企业缴税过低,事实真的如此简单吗?

据相关统计,亚马逊占有了全美44%的电子商务市场份额,64%的美国家庭是亚马逊会员,亚马逊还占有全美71%家庭智能音箱设备的市场。但据纽约大学市场学教授Scott Galloway的一篇最新的文章称,过去9年,亚马逊缴纳了14亿美元的企业所得税,而其竞争对手沃尔玛的企业所得税为640亿美元。

同期相比,沃尔玛在税收和股东分红之前的盈利为2290亿美元,亚马逊的盈利只有140亿美元。

另据研究显示,从2007至2015年,美国标普500上市公司的平均税负是其利润的27%。而美国科技四大巨头(Facebook、谷歌、苹果、亚马逊)的税负远没有达到这一平均值,其中,亚马逊的税负为13%,仅为平均税负的一半,甚至低于苹果的17%和谷歌的16%。

由此来看,特朗普以缴税过低对亚马逊“动手”确实有充足的依据,但其对于亚马逊的担心远非如此。

据金融研究平台Sentieo的一项调查显示,2017年美国上市公司财报和电话会议中,提及亚马逊的次数要远高于特朗普。

另据数据公司CB Insights 的统计,在2017 年,美国上市公司财报电话会议上被提及名字的公司,亚马逊被提及约3000 次,相当于苹果、谷歌、Facebook被提及次数总和的5倍左右。

这意味着,虽然特朗普赢下总统大选,但其带来的短期性政治风险远不及亚马逊带来的结构性经济风险,后者对企业的未来经营更具威胁性。最典型的表现就是“亚马逊效应”

所谓亚马逊效应,简单地说就是你的公司因为亚马逊进军你所在的行业而被摧毁,零售业就是典型的例子。

据统计,美国的零售业约有1200万工作面临亚马逊日益激烈的竞争,尤其是商场和购物中心商店的620万员工,他们销售家具、家电、电子产品、衣服、体育用品、书籍和综合日杂等产品。这些行业在统计学中称为GAFO(一般商品、服饰、家具与其他产品)。

GAFO是零售的中心,而亚马逊已经彻底改变这一市场,即GAFO商店的销售已经停滞不前,销售额在过去一年下滑了18亿美元(或0.6%),而零售业其余部分则增长了4%。同时,在线销售在去年第四季度增长了137亿美元,亚马逊占了其中的大多数。

据预测,如果亚马逊在5 年内拿下GAFO 40%的 市占率,150 万人恐将因此失业,若加上杂货店、药店、仓库和送货服务,亚马逊总计将导致超过200 万人失业。

与此同时,由于销售不济,整个实体零售业也正呈现被压缩之势。据统计,许多历史悠久的美国传统零售公司正在关闭其实体店。例如JCPenney正在关闭其140家实体店(约占14%);Macy's正在关闭100家实体店(约占15%);Sears正在关闭150家实体店(约占15%);CVS正在关闭70家实体店。

Kohl's计划缩小几乎所有实体店的规模。每一年,实体店关闭和破产的清单都在变得更长,相应导致失业的人数也会更多。据分析人士推测,每个这样的零售企业的倒闭,都会给亚马逊的市值增加50到100亿美元。

不仅如此,亚马逊只要宣布进入某个领域,该行业的上市公司股价就会迎来大幅波动(主要是下滑)。基于此,目前,约有18%美国零售商的债信评等被标准普尔(S&P)评为具有重大风险的CCC级或更低等级,约21%全美零售和餐饮业者被标普列在财务distressed名单内。

标普援引零售业陷困境的2大背后原因为难以适应网络零售和消费者品味的转变,而这均与亚马逊有直接的关系。

仅以去年10月的市值计算,亚马逊当时4270亿美元的市值就已经是包括沃尔玛、塔吉特、梅西百货、希尔斯百货等8家美国零售巨头公司的总和。而到了今年,由于亚马逊股价再次飙升,差距是只增不减。

以著名的希尔斯和沃尔玛为例,2009年至今,西尔斯市值从80亿美元缩水至4亿美元,而亚马逊市值则从360亿美元暴增到近5500亿美元。而2017年来,西尔斯股价跌了57%,亚马逊则涨了52%。与此类似,从2014年到2016年的三年间,沃尔玛的股价从74美元下降到了71美元(下降4%),而亚马逊从370美元上涨到845美元(增长128%)。

更夸张的是,今年1月,当亚马逊、摩根大通和伯克希尔•哈撒韦联合宣布成立非营利医疗健康公司,为其在美的 50 多万员工及家属提供医保服务时,30 家以上的医疗保险公司股价齐跌,总计蒸发市值超过300 亿美元。实际上,微软和苹果曾经也引发过类似的效应,但其产生情绪反应和持续时间远远不能和亚马逊相比。

最恐怖的是亚马逊未来还有很大的增长空间,即便是在上述的零售业。据统计,在美国仍有超过90%的零售销售额来自实体店。在一些大品类上,包括家居装饰品、个人护理产品、玩具和食品,实体店所占的份额甚至更高。随着线上销售的份额持续增加,亚马逊很可能会是最大的受益者。

据称,美国人在网上每花费1美元,亚马逊就拿走了大约44美分,与此同时它也在涉足实体零售,即除了拥有470多家全食超市门店外,自2015年以来,亚马逊已经开设了十多家书店和数十家销售Kindle及其他品牌配件的商场卖场。

它还在大学校园内或附近设有站点,提供零食、手机充电器以及其它的急需品,并作为包裹提取点。大约238个城市在为亚马逊第二家北美总部的落户竞标。

除了上述外,近期在云计算市场,业内也开始担心亚马逊效应的负面影响。众所周知,传统上,计算机运算能力由 IBM、惠普等公司承担,但让所有人没有想到的是,亚马逊作为一个电商,并没有技术基因的这样一个企业,居然进入到云计算的行业。

现在,Oracle、IBM、SAP、惠普、戴尔等这些我们心目当中鼎鼎大名的传统计算公司巨头市值加起来,总和都不如亚马逊。与此同时,微软、谷歌和IBM号称亚马逊云计算(AWS)的挑战者与其差距依然明显。

事实是,亚马逊在这类云计算服务上一直是无可争议的王者,但公司外部鲜很有人意识到AWS已经变得多有价值。在亚马逊内部,AWS是一个利润率如星巴克强健、年销售额高于Chipotle Mexican Grill连锁餐厅的部门。

为此,专家和业界人士目前越来越担心,在云计算市场,亚马逊也将垄断市场,损害竞争对手的利益。最典型的例子就是近期美国国防部数十亿美元的云计算采购招标,亚马逊可能获得全部合同。对此有相关专家表示,这种赢家通吃,不仅妨碍公平竞争,同时也给应用带来安全隐患,不利于产业的健康发展。

综上所述,我们认为,特朗普之所以要对亚马逊“动手”,除了税收的因素外,其更担心亚马逊效应带来的产业、社会外溢效应的负面影响,其实不仅是特朗普,业内也已经对包括亚马逊在内的美国科技四大巨头日趋垄断及给产业和社会外溢效应带来的负面影响表示了忧虑,毕竟以巨大的产业和社会资源牺牲为代价助极少数企业的成功,甚至垄断未必是一件好事。(本文仅代表作者观点

发现钛媒体,72问新生机;碎片时间,系统学习

点击阅读原文,订阅皮埃罗「72问」专栏,精彩不容错过



本话题在雪球有8条讨论,点击查看。
雪球是一个投资者的社交网络,聪明的投资者都在这里。
点击下载雪球手机客户端 http://xueqiu.com/xz

K-Means算法的10个有趣用例

$
0
0

摘要: 让我们走进K-Means算法的“前世今生”以及和它有关的十个有趣的应用案例。

K-means算法具有悠久的历史,并且也是最常用的聚类算法之一。K-means算法实施起来非常简单,因此,它非常适用于机器学习新手爱好者。首先我们来回顾K-Means算法的起源,然后介绍其较为典型的应用场景。

起源

1967年,James MacQueen在他的论文《用于多变量观测分类和分析的一些方法》中首次提出 “K-means”这一术语。1957年,贝尔实验室也将标准算法用于脉冲编码调制技术。1965年,E.W. Forgy发表了本质上相同的算法——Lloyd-Forgy算法。

什么是K-Means算法?

聚类,是将数据分成若干组,使得相同组中的数据点之间比其他组中的数据点更具有相似性。简而言之,聚类就是将具有相似特征的数据点分割成一个个组,也就是一个个聚类中。K-means算法的目标是在数据中查找一个个组,组的数量由变量K表示。根据数据所提供的特征,通过迭代运算将每个数据点分配给K个组中的其中一个组。下图中K = 2,因此可以从原始数据集中识别出两个聚类。

K-Means算法的10个有趣用例

在一个数据集上执行K-means算法,其输出分别是:

1.K中心点:从数据集中识别的k个聚类的每一个中心点。

2.数据集的完全标记,以确保每个数据点都可以分配给其中一个聚类。

K-Means算法的十大用例

K-means算法通常可以应用于维数、数值都很小且连续的数据集,比如:从随机分布的事物集合中将相同事物进行分组。

1.文档分类器

根据标签、主题和文档内容将文档分为多个不同的类别。这是一个非常标准且经典的K-means算法分类问题。首先,需要对文档进行初始化处理,将每个文档都用矢量来表示,并使用术语频率来识别常用术语进行文档分类,这一步很有必要。然后对文档向量进行聚类,识别文档组中的相似性。  这里是用于文档分类的K-means算法实现案例。

2.物品传输优化

使用K-means算法的组合找到无人机最佳发射位置和遗传算法来解决旅行商的行车路线问题,优化无人机物品传输过程。 这是该项目的白皮书。

3.识别犯罪地点

使用城市中特定地区的相关犯罪数据,分析犯罪类别、犯罪地点以及两者之间的关联,可以对城市或区域中容易犯罪的地区做高质量的勘察。 这是基于德里飞行情报区犯罪数据的论文。

4.客户分类

聚类能过帮助营销人员改善他们的客户群(在其目标区域内工作),并根据客户的购买历史、兴趣或活动监控来对客户类别做进一步细分。 是关于电信运营商如何将预付费客户分为充值模式、发送短信和浏览网站几个类别的白皮书。对客户进行分类有助于公司针对特定客户群制定特定的广告。

5.球队状态分析

分析球员的状态一直都是体育界的一个关键要素。随着竞争越来愈激烈,机器学习在这个领域也扮演着至关重要的角色。如果你想创建一个优秀的队伍并且喜欢根据球员状态来识别类似的球员,那么K-means算法是一个很好的选择。具体细节和实现请参照 这篇文章

6.保险欺诈检测

机器学习在欺诈检测中也扮演着一个至关重要的角色,在汽车、医疗保险和保险欺诈检测领域中广泛应用。利用以往欺诈性索赔的历史数据,根据它和欺诈性模式聚类的相似性来识别新的索赔。由于保险欺诈可能会对公司造成数百万美元的损失,因此欺诈检测对公司来说至关重要。 这是汽车保险中使用聚类来检测欺诈的白皮书。

7.乘车数据分析

面向大众公开的Uber乘车信息的数据集,为我们提供了大量关于交通、运输时间、高峰乘车地点等有价值的数据集。分析这些数据不仅对Uber大有好处,而且有助于我们对城市的交通模式进行深入的了解,来帮助我们做城市未来规划。 这是一篇使用单个样本数据集来分析Uber数据过程的文章。

8.网络分析犯罪分子

网络分析是从个人和团体中收集数据来识别二者之间的重要关系的过程。网络分析源自于犯罪档案,该档案提供了调查部门的信息,以对犯罪现场的罪犯进行分类。 这是一篇在学术环境中,如何根据用户数据偏好对网络用户进行 cyber-profile的论文。

9.呼叫记录详细分析

通话详细记录(CDR)是电信公司在对用户的通话、短信和网络活动信息的收集。将通话详细记录与客户个人资料结合在一起,这能够帮助电信公司对客户需求做更多的预测。在 这篇文章中,你将了解如何使用无监督K-Means聚类算法对客户一天24小时的活动进行聚类,来了解客户数小时内的使用情况。

10.IT警报的自动化聚类

大型企业IT基础架构技术组件(如网络,存储或数据库)会生成大量的警报消息。由于警报消息可以指向具体的操作,因此必须对警报信息进行手动筛选,确保后续过程的优先级。 对数据进行聚类可以对警报类别和平均修复时间做深入了解,有助于对未来故障进行预测。

以上为译文。

本文由阿里云云栖社区组织翻译。

文章原标题《10 Interesting Use Cases For the K-Means Algorithm》,译者:Mags,审校:袁虎。

AI芯片全球战局:中国公司各自为政,何以抗衡全球技术寡头|界面新闻 · JMedia

$
0
0

作者:吴军宁  中科院自动化所集成中心

如果说 2016 年 3 月份 AlphaGo 与李世石的那场人机大战只在科技界和围棋界产生较大影响的话,那么 2017 年 5 月其与排名第一的世界围棋冠军柯洁的对战则将人工智能技术推向了公众视野。阿尔法狗(AlphaGo)是第一个击败人类职业围棋选手、第一个战胜围棋世界冠军的人工智能程序,由谷歌(Google)旗下 DeepMind 公司戴密斯 · 哈萨比斯领衔的团队开发,其主要工作原理是 “深度学习”。

其实早在 2012 年,深度学习技术就已经在学术界引起了广泛地讨论。在这一年的 ImageNet 大规模视觉识别挑战赛 ILSVRC 中,采用 5 个卷积层和 3 个全连接层的神经网络结构 AlexNet,取得了 top-5(15.3%)的历史最佳错误率,而第二名的成绩仅为 26.2%。从此以后,就出现了层数更多、结构更为复杂的神经网络结构,如 ResNet、GoogleNet、VGGNet 和 MaskRCNN 等,还有去年比较火的生成式对抗网络 GAN。

不论是赢得视觉识别挑战赛的 AlexNet,还是击败围棋冠军柯洁的 AlphaGo,它们的实现都离不开现代信息技术的核心——处理器,不论这个处理器是传统的 CPU,还是 GPU,还是新兴的专用加速部件 NNPU(NNPU 是 Neural Network Processing Unit 的简称)。在计算机体系结构国际顶级会议 ISCA2016 上有个关于体系结构 2030 的小型研讨会,名人堂成员 UCSB 的谢源教授就对 1991 年以来在 ISCA 收录的论文进行了总结,专用加速部件相关的论文收录是在 2008 年开始,而在 2016 年达到了顶峰,超过了处理器、存储器以及互联结构等三大传统领域。而在这一年,来自中国科学院计算技术研究所的陈云霁、陈天石研究员课题组提交的《一种神经网络指令集》论文,更是 ISCA2016 最高得分论文。

在具体介绍 AI 芯片国内外之前,看到这里有部分读者或许会产生这样的疑惑:这不都是在说神经网络和深度学习吗?那么我觉得有必要对人工智能和神经网络的概念进行阐述,特别是 2017 年工信部发布的《促进新一代人工智能产业发展三年行动计划(2018-2020 年)》中,对发展目标的描述很容易让人觉得人工智能就是神经网络,AI 芯片就是神经网络芯片。

人工智能整体核心基础能力显著增强,智能传感器技术产品实现突破,设计、代工、封测技术达到国际水平,神经网络芯片实现量产并在重点领域实现规模化应用,开源开发平台初步具备支撑产业快速发展的能力。

其实则不然。人工智能是一个很老很老的概念,而神经网络只不过是人工智能范畴的一个子集。早在 1956 年,被誉为 “人工智能之父” 的图灵奖得主约翰 · 麦卡锡就这样定义人工智能:创造智能机器的科学与工程。而在 1959 年,Arthur Samuel 给出了人工智能的一个子领域机器学习的定义,即“计算机有能力去学习,而不是通过预先准确实现的代码”,这也是目前公认的对机器学习最早最准确的定义。而我们日常所熟知的神经网络、深度学习等都属于机器学习的范畴,都是受大脑机理启发而发展得来的。另外一个比较重要的研究领域就是脉冲神经网络,国内具有代表的单位和企业是清华大学类脑计算研究中心和上海西井科技等。

好了,现在终于可以介绍 AI 芯片国内外的发展现状了,当然这些都是我个人的一点观察和愚见,管窥之见权当抛砖引玉。

国外:技术寡头,优势明显

由于具有得天独厚的技术和应用优势,英伟达和谷歌几乎占据了人工智能处理领域 80% 的市场份额,而且在谷歌宣布其 Cloud TPU 开放服务和英伟达推出自动驾驶处理器 Xavier 之后,这一份额占比在 2018 年有望进一步扩大。其他厂商,如英特尔、特斯拉、ARM、IBM 以及 Cadence 等,也在人工智能处理器领域占有一席之地。

当然,上述这些公司的专注领域却不尽相同。比如英伟达主要专注于 GPU 和无人驾驶领域,而谷歌则主要针对云端市场,英特尔则主要面向计算机视觉,Cadence 则以提供加速神经网络计算相关 IP 为主。如果说前述这些公司还主要偏向处理器设计等硬件领域,那么ARM 公司则主要偏向软件,致力于针对机器学习和人工智能提供高效算法库。

注:上述表格中所给为截止到 2017 年各研制单位公开可查的最新数据。

独占鳌头——英伟达

在人工智能领域,英伟达可以说是目前涉及面最广、市场份额最大的公司,旗下产品线遍布自动驾驶汽车、高性能计算、机器人、医疗保健、云计算、游戏视频等众多领域。其针对自动驾驶汽车领域的全新人工智能超级计算机  Xavier,用 NVIDIA 首席执行官黄仁勋的话来说就是 “这是我所知道的 SoC 领域非常了不起的尝试,我们长期以来一直致力于开发芯片。”

Xavier 是一款完整的片上系统 (SoC),集成了被称为 Volta 的全新 GPU 架构、定制 8 核 CPU 架构以及新的计算机视觉加速器。该处理器提供 20 TOPS(万亿次运算 / 秒)的高性能,而功耗仅为 20 瓦。单个 Xavier 人工智能处理器包含 70 亿个晶体管,采用最前沿的 16nm FinFET 加工技术进行制造,能够取代目前配置了两个移动 SoC 和两个独立 GPU 的 DRIVE PX 2,而功耗仅仅是它的一小部分。

而在 2018 年拉斯维加斯 CES 展会上,NVIDIA 又推出了三款基于 Xavier 的人工智能处理器,包括一款专注于将增强现实(AR)技术应用于汽车的产品、一款进一步简化车内人工智能助手构建和部署的 DRIVE IX 和一款对其现有自主出租车大脑——Pegasus 的修改,进一步扩大自己的优势。

产学研的集大成者——谷歌

如果你只是知道谷歌的 AlphaGo、无人驾驶和 TPU 等这些人工智能相关的产品,那么你还应该知道这些产品背后的技术大牛们:谷歌传奇芯片工程师 Jeff Dean、谷歌云计算团队首席科学家、斯坦福大学 AI 实验室主管李飞飞、Alphabet 董事长 John Hennessy 和谷歌杰出工程师 David Patterson。

时至今日,摩尔定律遇到了技术和经济上的双重瓶颈,处理器性能的增长速度越来越慢,然而社会对于计算能力的需求增速却并未减缓,甚至在移动应用、大数据、人工智能等新的应用兴起后,对于计算能力、计算功耗和计算成本等提出了新的要求。与完全依赖于通用 CPU 及其编程模型的传统软件编写模式不同,异构计算的整个系统包含了多种基于特定领域架构(Domain-Specific Architecture, DSA)设计的处理单元,每一个 DSA 处理单元都有负责的独特领域并针对该领域做优化,当计算机系统遇到相关计算时便由相应的 DSA 处理器去负责。而谷歌就是异构计算的践行者,TPU 就是异构计算在人工智能应用的一个很好例子。

2017 年发布的第二代 TPU 芯片,不仅加深了人工智能在学习和推理方面的能力,而且谷歌是认真地要将它推向市场。根据谷歌的内部测试,第二代芯片针对机器学习的训练速度能比现在市场上的图形芯片(GPU)节省一半时间;第二代 TPU 包括了四个芯片,每秒可处理 180 万亿次浮点运算;如果将 64 个 TPU 组合到一起,升级为所谓的 TPU Pods,则可提供大约 11500 万亿次浮点运算能力。

计算机视觉领域的搅局者——英特尔

英特尔作为世界上最大的计算机芯片制造商,近年来一直在寻求计算机以外的市场,其中人工智能芯片争夺成为英特尔的核心战略之一。为了加强在人工智能芯片领域的实力,不仅以 167 亿美元收购 FPGA 生产商 Altera 公司,还以 153 亿美元收购自动驾驶技术公司 Mobileye,以及机器视觉公司 Movidius 和为自动驾驶汽车芯片提供安全工具的公司 Yogitech,背后凸显这家在 PC 时代处于核心位置的巨头面向未来的积极转型。

Myriad X 就是英特尔子公司 Movidius 在 2017 年推出的视觉处理器 (VPU,vision processing unit),这是一款低功耗的系统芯片 (SoC),用于在基于视觉的设备上加速深度学习和人工智能——如无人机、智能相机和 VR / AR 头盔。Myriad X 是全球第一个配备专用神经网络计算引擎的片上系统芯片(SoC),用于加速设备端的深度学习推理计算。该神经网络计算引擎是芯片上集成的硬件模块,专为高速、低功耗且不牺牲精确度地运行基于深度学习的神经网络而设计,让设备能够实时地看到、理解和响应周围环境。引入该神经计算引擎之后,Myriad X 架构能够为基于深度学习的神经网络推理提供 1TOPS 的计算性能。

执 “能效比” 之牛耳——学术界

除了工业界和厂商在人工智能领域不断推出新产品之外,学术界也在持续推进人工智能芯片新技术的发展。

比利时鲁汶大学的 Bert Moons 等在 2017 年顶级会议 IEEE ISSCC 上面提出了能效比高达 10.0TOPs/W 的针对卷积神经网络加速的芯片 ENVISION,该芯片采用 28nm FD-SOI 技术。该芯片包括一个 16 位的 RISC 处理器核,1D-SIMD 处理单元进行 ReLU 和 Pooling 操作,2D-SIMD MAC 阵列处理卷积层和全连接层的操作,还有 128KB 的片上存储器。

韩国科学技术院 KAIST 的 Dongjoo Shin 等人在 ISSCC2017 上提出了一个针对 CNN 和 RNN 结构可配置的加速器单元 DNPU,除了包含一个 RISC 核之外,还包括了一个针对卷积层操作的计算阵列 CP 和一个针对全连接层 RNN-LSTM 操作的计算阵列 FRP,相比于鲁汶大学的 Envision,DNPU 支持 CNN 和 RNN 结构,能效比高达 8.1TOPS/W。该芯片采用了 65nm CMOS 工艺。

相比较于鲁汶大学和韩国科学技术院都针对神经网络推理部分的计算操作来说,普渡大学的Venkataramani S 等人在计算机体系结构顶级会议 ISCA2017 上提出了针对大规模神经网络训练的人工智能处理器 SCALLDEEP。

该论文针对深度神经网络的训练部分进行针对性优化,提出了一个可扩展服务器架构,且深入分析了深度神经网络中卷积层,采样层,全连接层等在计算密集度和访存密集度方面的不同,设计了两种处理器 core 架构,计算密集型的任务放在了 comHeavy 核中,包含大量的 2D 乘法器和累加器部件,而对于访存密集型任务则放在了 memHeavy 核中,包含大量 SPM 存储器和 tracker 同步单元,既可以作为存储单元使用,又可以进行计算操作,包括 ReLU,tanh 等。而一个 SCALEDEEP Chip 则可以有不同配置下的两类处理器核组成,然后再组成计算簇。

论文中所用的处理平台包括 7032 个处理器 tile。论文作者针对深度神经网络设计了编译器,完成网络映射和代码生成,同时设计了设计空间探索的模拟器平台,可以进行性能和功耗的评估,性能则得益于时钟精确级的模拟器,功耗评估则从 DC 中提取模块的网表级的参数模型。该芯片仅采用了 Intel 14nm 工艺进行了综合和性能评估,峰值能效比高达 485.7GOPS/W。

国内:百家争鸣,各自为政

可以说,国内各个单位在人工智能处理器领域的发展和应用与国外相比依然存在很大的差距。由于我国特殊的环境和市场,国内人工智能处理器的发展呈现出百花齐放、百家争鸣的态势,这些单位的应用领域遍布股票交易、金融、商品推荐、安防、早教机器人以及无人驾驶等众多领域,催生了大量的人工智能芯片创业公司,如地平线、深鉴科技、中科寒武纪等。尽管如此,国内起步较早的中科寒武纪却并未如国外大厂一样形成市场规模,与其他厂商一样,存在着各自为政的散裂发展现状。

除了新兴创业公司,国内研究机构如北京大学、清华大学、中国科学院等在人工智能处理器领域都有深入研究;而其他公司如百度和比特大陆等,2017 年也有一些成果发布。

注:上述表格中所给为截止到 2017 年各研制单位公开可查的最新数据。

全球 AI 芯片界首个独角兽——寒武纪

2017 年 8 月,国内 AI 芯片初创公司寒武纪宣布已经完成 1 亿美元 A 轮融资,战略投资方可谓阵容豪华,阿里巴巴、联想、科大讯飞等企业均参与投资。而其公司也成为全球 AI 芯片界首个独角兽,受到国内外市场广泛关注。

寒武纪科技主要负责研发生产 AI 芯片,公司最主要的产品为 2016 年发布的寒武纪 1A 处理器 (Cambricon-1A),是一款可以深度学习的神经网络专用处理器,面向智能手机、无人机、安防监控、可穿戴设备以及智能驾驶等各类终端设备,在运行主流智能算法时性能功耗比全面超越传统处理器。目前已经研发出 1A、1H 等多种型号。与此同时,寒武纪也推出了面向开发者的寒武纪人工智能软件平台 Cambricon NeuWare,包含开发、调试和调优三大部分。

软硬件协同发展的典范——深鉴科技

深鉴科技的联合创始人韩松在不同场合曾多次提及软硬件协同设计对人工智能处理器的重要性,而其在 FPGA 领域顶级会议 FPGA2017 最佳论文 ESE 硬件架构就是最好的证明。该项工作聚焦于使用 LSTM 进行语音识别的场景,结合深度压缩(Deep Compression)、专用编译器以及 ESE 专用处理器架构,在中端的 FPGA 上即可取得比 Pascal Titan X GPU 高 3 倍的性能,并将功耗降低 3.5 倍。

在 2017 年 10 月的时候,深鉴科技推出了六款 AI 产品,分别是人脸检测识别模组、人脸分析解决方案、视频结构化解决方案、ARISTOTLE 架构平台,深度学习 SDK DNNDK、双目深度视觉套件。而在人工智能芯片方面,公布了最新的芯片计划,由深鉴科技自主研发的芯片 “听涛”、“观海” 将于 2018 年第三季度面市,该芯片采用台积电 28nm 工艺,亚里士多德架构,峰值性能 3.7 TOPS/W。

对标谷歌 TPU——比特大陆算丰

作为比特币独角兽的比特大陆,在 2015 年开始涉足人工智能领域,其在 2017 年发布的 面向 AI 应用的张量处理器算丰 Sophon BM1680,是继谷歌 TPU 之后,全球又一款专门用于张量计算加速的专用芯片(ASIC),适用于 CNN / RNN / DNN 的训练和推理。

BM1680 单芯片能够提供 2TFlops 单精度加速计算能力,芯片由 64 NPU 构成,特殊设计的 NPU 调度引擎(Scheduling Engine)可以提供强大的数据吞吐能力,将数据输入到神经元核心(Neuron Processor Cores)。BM1680 采用改进型脉动阵列结构。2018 年比特大陆将发布第 2 代算丰 AI 芯片 BM1682,计算力将有大幅提升。

百家争鸣——百度、地平线及其他

在 2017 年的 HotChips 大会上,百度发布了XPU,这是一款 256 核、基于 FPGA 的云计算加速芯片,用于百度的人工智能、数据分析、云计算以及无人驾驶业务。在会上,百度研究员欧阳剑表示,百度设计的芯片架构突出多样性,着重于计算密集型、基于规则的任务,同时确保效率、性能和灵活性的最大化。

欧阳剑表示:“FPGA 是高效的,可以专注于特定计算任务,但缺乏可编程能力。传统 CPU 擅长通用计算任务,尤其是基于规则的计算任务,同时非常灵活。GPU 瞄准了并行计算,因此有很强大的性能。XPU 则关注计算密集型、基于规则的多样化计算任务,希望提高效率和性能,并带来类似 CPU 的灵活性。

在 2018 年百度披露更多关于 XPU 的相关信息。

2017 年 12 月底,人工智能初创企业地平线发布了中国首款全球领先的嵌入式人工智能芯片—— 面向智能驾驶的征程(Journey)1.0 处理器和面向智能摄像头的旭日(Sunrise)1.0 处理器,还有针对智能驾驶、智能城市和智能商业三大应用场景的人工智能解决方案。“旭日 1.0”和 “征程 1.0” 是完全由地平线自主研发的人工智能芯片,具有全球领先的性能。

为了解决应用场景中的问题,地平线将算法与芯片做了强耦合,用算法来定义芯片,提升芯片的效率,在高性能的情况下可以保证它的低功耗、低成本。具体芯片参数尚无公开数据。

除了百度和地平线,国内研究机构如中国科学院、北京大学和清华大学也有人工智能处理器相关的成果发布。

北京大学联合商汤科技等提出一种基于 FPGA 的快速 Winograd 算法,可以大幅降低算法复杂度,改善 FPGA 上的 CNN 性能。论文中的实验使用当前最优的多种 CNN 架构(如 AlexNet 和 VGG16),从而实现了 FPGA 加速之下的最优性能和能耗。在 Xilinx ZCU102 平台上达到了卷积层平均处理速度 1006.4 GOP/s,整体 AlexNet 处理速度 854.6 GOP/s,卷积层平均处理速度 3044.7 GOP/s,整体 VGG16 的处理速度 2940.7 GOP/s。

中国科学院计算机体系结构国家重点实验室在顶级会议 HPCA2017 上提出了一种基于数据流的神经网络处理器架构,以便适应特征图、神经元和突触等不同层级的并行计算,为了实现这一目标,该团队对单个处理单元 PE 进行重新设计,使得操作数可以直接通过横向或纵向的总线从片上存储器获取,而非传统 PE 只能从上至下或从左至右由相邻单元获取。该芯片采用了 TMSC 65nm 工艺,峰值性能为 490.7 GOPs/W。

清华大学微纳电子系魏少军等 2017 年的 VLSI 国际研讨会上提出了基于可重构多模态混合的神经计算芯片 Thinker。Thinker 芯片基于该团队长期积累的可重构计算芯片技术,采用可重构架构和电路技术,突破了神经网络计算和访存的瓶颈,实现了高能效多模态混合神经网络计算。Thinker 芯片具有高能效的突出优点,其能量效率相比目前在深度学习中广泛使用的 GPU 提升了三个数量级。Thinker 芯片支持电路级编程和重构,是一个通用的神经网络计算平台,可广泛应用于机器人、无人机、智能汽车、智慧家居、安防监控和消费电子等领域。该芯片采用了 TSMC 65nm 工艺,片上存储为 348KB,峰值性能为 5.09TOPS/W。

新架构新技术——忆阻器

2017 年清华大学微电子所钱鹤、吴华强课题组在《自然通讯》(Nature Communications)在线发表了题为 “运用电子突触进行人脸分类”(“Face Classification using Electronic Synapses”)的研究成果,将氧化物忆阻器的集成规模提高了一个数量级,首次实现了基于 1024 个氧化物忆阻器阵列的类脑计算。该成果在最基本的单个忆阻器上实现了存储和计算的融合,采用完全不同于传统 “冯 · 诺依曼架构” 的体系,可以使芯片功耗降低到原千分之一以下。忆阻器被认为是最具潜力的电子突触器件,通过在器件两端施加电压,可以灵活地改变其阻值状态,从而实现突触的可塑性。此外,忆阻器还具有尺寸小、操作功耗低、可大规模集成等优势。因此,基于忆阻器所搭建的类脑计算硬件系统具有功耗低和速度快的优势,成为国际研究热点。

在神经形态处理器方面,最为著名的就是 IBM 在 2014 年推出的 TrueNorth 芯片,该芯片包括 4096 个核心和 540 万个晶体管,功耗 70mW,模拟了一百万个神经元和 2.56 亿个突触。而在 2017 年,英特尔也推出一款能模拟大脑工作的自主学习芯片 Loihi,Loihi 由 128 个计算核心构成,每个核心集成了 1024 个人工神经元,整个芯片拥有超过个 13 万个神经元与 1.3 亿个突触连接,与人脑超过 800 亿个神经元相比,简直是小巫见大巫,Loihi 的运算规模仅比虾脑复杂一点点而已。英特尔认为该芯片适用于无人机与汽车自动驾驶,红绿灯自适应路面交通状况,用摄像头寻找失踪人口等任务。

而在神经形态芯片研究领域,清华大学类脑计算研究中心施路平等在 2015 年就推出了首款类脑芯片—“天机芯”,该芯片世界首次将人工神经网络(Artificial Neural Networks, ANNs)和脉冲神经网络(Spiking Neural Networks,SNNs)进行异构融合,同时兼顾技术成熟并被广泛应用的深度学习模型与未来具有巨大前景的计算神经科学模型,可用于诸如图像处理、语音识别、目标跟踪等多种应用开发。在类脑 “自行” 车演示平台上,集成 32 个天机一号芯片,实现了面向视觉目标探测、感知、目标追踪、自适应姿态控制等任务的跨模态类脑信息处理实验。据悉,基于 TSMC 28nm 工艺的第二代天机芯片也即将推出,性能将会得到极大提升。

从 ISSCC2018 看人工智能芯片发展趋势

在刚刚结束的计算机体系结构顶级会议 ISSCC2018,“Digital Systems: Digital Architectures and Systems” 分论坛主席 Byeong-Gyu Nam 对人工智能芯片,特别是深度学习芯片的发展趋势做了概括。深度学习依然今年大会最为热门的话题。相比较于去年大多数论文都在讨论卷积神经网络的实现问题,今年则更加关注两个问题:其一,如果更高效地实现卷积神经网络,特别是针对手持终端等设备;其二,则是关于全连接的非卷积神经网络,如 RNN 和 LSTM 等。

同时,为了获得更高的能效比,越来越多的研究者把精力放在了低精度神经网络的设计和实现,如 1bit 的神经网络。这些新型技术,使得深度学习加速器的能效比从去年的几十 TOPS/W 提升到了今年的上百 TOPS/W。有些研究者也对数字 + 模拟的混合信号处理实现方案进行了研究。对数据存取具有较高要求的全连接网络,有些研究者则借助 3-D 封装技术来获得更好的性能。

总结:对国产人工智能芯片的一点愚见

正如前文所述,在人工智能芯片领域,国外芯片巨头占据了绝大部分市场份额,不论是在人才聚集还是公司合并等方面,都具有绝对的领先优势。而国内人工智能初创公司则又呈现百家争鸣、各自为政的纷乱局面;特别是每个初创企业的人工智能芯片都具有自己独特的体系结构和软件开发套件,既无法融入英伟达和谷歌建立的生态圈,又不具备与之抗衡的实力。

国产人工智能芯片的发展,一如早年间国产通用处理器和操作系统的发展,过份地追求完全独立、自主可控的怪圈,势必会如众多国产芯片一样逐渐退出历史舞台。借助于 X86 的完整生态,短短一年之内,兆芯推出的国产自主可控 x86 处理器,以及联想基于兆芯 CPU 设计生产的国产计算机、服务器就获得全国各地党政办公人员的高度认可,并在党政军办公、信息化等国家重点系统和工程中已获批量应用。

当然,投身于 X86 的生态圈对于通用桌面处理器和高端服务器芯片来说无可厚非,毕竟创造一个如 Wintel 一样的生态链已绝非易事,我们也不可能遇见第二个乔布斯和苹果公司。而在全新的人工智能芯片领域,对众多国产芯片厂商来说,还有很大的发展空间,针对神经网络加速器最重要的就是找到一个具有广阔前景的应用领域,如华为海思麒麟处理器之于中科寒武纪的 NPU;否则还是需要融入一个合适的生态圈。另外,目前大多数国产人工智能处理器都针对于神经网络计算进行加速,而能够提供单芯片解决方案的很少;微控制器领域的发展,ARM 的 Cortex-A 系列和 Cortex-M 系列占据主角,但是新兴的开源指令集架构 RISC-V 也不容小觑,完全值得众多国产芯片厂商关注。

本文转载自中国科学院自动化研究所

来源:中科院自动化所集成中心

编辑:鲁宁、欧梨成


美团打车上海上线7天:服务220万人次,4成为吃喝玩乐

$
0
0

腾讯《一线》作者相欣

4 月 2 日,美团打车宣布截止到 3 月 27 日 24 点,美团打车登陆上海满 7 天,一周时间内,美团打车在上海累计服务乘客超 220 万人次。美团打车称,在全部已完成订单中,40% 订单去往吃喝玩乐等生活服务场景。这与美团点评的餐饮、到店综合及酒旅等业务形成协同。

3 月 21 日,美团打车上海站开通,同时上线出租车和快车两种业务。美团数据显示,上线 3 天,美团打车在上海日完成订单量就突破 15 万单,并在随后几天持续上涨。第二天日订单量达 25 万单,第三天就突破 30 万,司机平均接单时长 5 秒。随后几天内,美团打车上海日完成订单量始终保持在 30 万单以上。

数字背后折射出用户的旺盛需求。在上海上线 7 天内,平台累计服务乘客近 220 万人次。在所有已完成订单当中,40% 与吃喝玩乐等休闲娱乐场景相关,其中最受欢迎的商圈是南京西路。上线后首个周末两天(3 月 24 日,3 月 25 日),通过美团 APP 餐饮商户页面打车入口完成的订单,环比周五(3 月 23 日)增长 70%。

美团方面称,四成订单和吃喝玩乐相关,再次表明出行与美团点评生活服务业务的协同。周末餐饮商户页面入口打车订单的增长,也进一步表明吃喝玩乐与出行的串联效应。此外,在区域占比方面,浦东新区用户最爱用美团打车,全市各区域全部订单的 24% 来自浦东新区,其次分别是闵行区 10%、松江区7%。

美团打车相关负责人表示,美团点评的使命是“让大家吃得更好,生活更好”,希望通过美团打车来满足平台用户的出行需求,为用户提供一站式“吃喝玩乐”服务体验,同时给用户多一个出行选择。

本文链接

对比公共 DNS 服务的性能

$
0
0
Google 的 8.8.8.8,CloudFlare 的 1.1.1.1,Quad9 的 9.9.9.9,OpenDNS 的 208.67.222.222...越来越多的企业和机构提供了免费的公共 DNS 解析服务,但它们的性能究竟谁更胜一筹,解析速度究竟有多快?有研究者利用了全球 18 个位置(不包括中国) 测试了这些 DNS 服务的性能。除了 Yandex 的 77.88.8.7,所有 DNS 服务在北美和欧洲的响应速度都在 15ms 以内,也就是说如果你生活在这些地区,你可以选择任意的公共 DNS 服务。CloudFlare 的服务平均速度最快,全球平均响应速度仅仅为 4.98 ms,Google 和 Quad9 位居第二和第三,Quad9 在北美和欧洲比 Google 快,但在亚洲和南美比较慢;Yandex 只在俄罗斯比较快,其它地方都很慢。

调查发现:成年人在金融知识方面表现得很欠缺

$
0
0

62825888363184284.jpg

测试的部分内容包括将基本数字技能应用于日常财务任务的问题。

大约四分之一的成年人无法计算出他们在购买少量商品时应该被找回多少零钱,而在西班牙、英国和意大利等国,这一比例上升到三分之一左右。

三分之一的成年人在为一种产品支付“单位”(例如每公升每公斤)价格时,很难计算出他们要支付的价格。

在31个国家中,大约有一半的人无法阅读简单的金融图表,这类图表通常用来传递经济和金融产品的关键信息,而在一些国家(如希腊、智利、意大利、土耳其),这一比例高达四分之三。

大多数成年人都很难计算出更大的折扣,涉及更复杂的计算。

表现最好的是爱沙尼亚、芬兰、日本、新加坡和奥地利的居民。而土耳其、智利、以色列、意大利、西班牙和英国的居民则表现不佳。

谈到性别差异时,女性往往更擅长基本的财务任务;但在另外三个问题,计算单位成本、从图表中解读财务信息、计算折扣,则显示了男性的显著优势。

有趣的是,这种差异在35岁以上的成年人中表现更明显,但在16-25岁的人群组中则表现得不那么明显。这表明一些地方的金融教育正在得到改善。

访问:

阿里云

消息中间件选型分析——从Kafka与RabbitMQ的对比来看全局

$
0
0

有很多网友留言:公司要做消息中间件选型,该如何选?你觉得哪个比较好?消息选型的确是一个大论题,实则说来话长的事情又如何长话短说。对此笔者专门撰稿一篇内功心法: 如何看待消息中间件的选型,不过这篇只表其意未表其行,为了弥补这种缺陷,笔者最近特意重新撰稿一篇,以供参考。温馨提示:本文一万多字,建议先马(关注)后看。

一、前言

消息队列中间件(简称消息中间件)是指利用高效可靠的消息传递机制进行与平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息排队模型,它可以在分布式环境下提供应用解耦、弹性伸缩、冗余存储、流量削峰、异步通信、数据同步等等功能,其作为分布式系统架构中的一个重要组件,有着举足轻重的地位。

目前开源的消息中间件可谓是琳琅满目,能让大家耳熟能详的就有很多,比如ActiveMQ、RabbitMQ、Kafka、RocketMQ、ZeroMQ等。不管选择其中的哪一款,都会有用的不趁手的地方,毕竟不是为你量身定制的。有些大厂在长期的使用过程中积累了一定的经验,其消息队列的使用场景也相对稳定固化,或者目前市面上的消息中间件无法满足自身需求,并且也具备足够的精力和人力而选择自研来为自己量身打造一款消息中间件。但是绝大多数公司还是不会选择重复造轮子,那么选择一款合适自己的消息中间件显得尤为重要。就算是前者,那么在自研出稳定且可靠的相关产品之前还是会经历这样一个选型过程。

在整体架构中引入消息中间件,势必要考虑很多因素,比如成本及收益问题,怎么样才能达到最优的性价比?虽然消息中间件种类繁多,但是各自都有各自的侧重点,选择合适自己、扬长避短无疑是最好的方式。如果你对此感到无所适从,本文或许可以参考一二。


二、各类消息队列简述

ActiveMQ是Apache出品的、采用Java语言编写的完全基于JMS1.1规范的面向消息的中间件,为应用程序提供高效的、可扩展的、稳定的和安全的企业级消息通信。不过由于历史原因包袱太重,目前市场份额没有后面三种消息中间件多,其最新架构被命名为Apollo,号称下一代ActiveMQ,有兴趣的同学可行了解。

RabbitMQ是采用Erlang语言实现的AMQP协议的消息中间件,最初起源于金融系统,用于在分布式系统中存储转发消息。RabbitMQ发展到今天,被越来越多的人认可,这和它在可靠性、可用性、扩展性、功能丰富等方面的卓越表现是分不开的。

Kafka起初是由LinkedIn公司采用Scala语言开发的一个分布式、多分区、多副本且基于zookeeper协调的分布式消息系统,现已捐献给Apache基金会。它是一种高吞吐量的分布式发布订阅消息系统,以可水平扩展和高吞吐率而被广泛使用。目前越来越多的开源分布式处理系统如Cloudera、Apache Storm、Spark、Flink等都支持与Kafka集成。

RocketMQ是阿里开源的消息中间件,目前已经捐献个Apache基金会,它是由Java语言开发的,具备高吞吐量、高可用性、适合大规模分布式系统应用等特点,经历过双11的洗礼,实力不容小觑。

ZeroMQ号称史上最快的消息队列,基于C语言开发。ZeroMQ是一个消息处理队列库,可在多线程、多内核和主机之间弹性伸缩,虽然大多数时候我们习惯将其归入消息队列家族之中,但是其和前面的几款有着本质的区别,ZeroMQ本身就不是一个消息队列服务器,更像是一组底层网络通讯库,对原有的Socket API上加上一层封装而已。

目前市面上的消息中间件还有很多,比如腾讯系的PhxQueue、CMQ、CKafka,又比如基于Go语言的NSQ,有时人们也把类似Redis的产品也看做消息中间件的一种,当然它们都很优秀,但是本文篇幅限制无法穷极所有,下面会针对性的挑选RabbitMQ和Kafka两款典型的消息中间件来做分析,力求站在一个公平公正的立场来阐述消息中间件选型中的各个要点。


三、选型要点概述

衡量一款消息中间件是否符合需求需要从多个维度进行考察,首要的就是功能维度,这个直接决定了你能否最大程度上的实现开箱即用,进而缩短项目周期、降低成本等。如果一款消息中间件的功能达不到想要的功能,那么就需要进行二次开发,这样会增加项目的技术难度、复杂度以及增大项目周期等。

1. 功能维度

功能维度又可以划分个多个子维度,大致可以分为以下这些:

  • 优先级队列

优先级队列不同于先进先出队列,优先级高的消息具备优先被消费的特权,这样可以为下游提供不同消息级别的保证。不过这个优先级也是需要有一个前提的:如果消费者的消费速度大于生产者的速度,并且消息中间件服务器(一般简单的称之为Broker)中没有消息堆积,那么对于发送的消息设置优先级也就没有什么实质性的意义了,因为生产者刚发送完一条消息就被消费者消费了,那么就相当于Broker中至多只有一条消息,对于单条消息来说优先级是没有什么意义的。

  • 延迟队列

当你在网上购物的时候是否会遇到这样的提示:“三十分钟之内未付款,订单自动取消”?这个是延迟队列的一种典型应用场景。延迟队列存储的是对应的延迟消息,所谓“延迟消息”是指当消息被发送以后,并不想让消费者立刻拿到消息,而是等待特定时间后,消费者才能拿到这个消息进行消费。延迟队列一般分为两种:基于消息的延迟和基于队列的延迟。基于消息的延迟是指为每条消息设置不同的延迟时间,那么每当队列中有新消息进入的时候就会重新根据延迟时间排序,当然这也会对性能造成极大的影响。实际应用中大多采用基于队列的延迟,设置不同延迟级别的队列,比如5s、10s、30s、1min、5mins、10mins等,每个队列中消息的延迟时间都是相同的,这样免去了延迟排序所要承受的性能之苦,通过一定的扫描策略(比如定时)即可投递超时的消息。

  • 死信队列

由于某些原因消息无法被正确的投递,为了确保消息不会被无故的丢弃,一般将其置于一个特殊角色的队列,这个队列一般称之为死信队列。与此对应的还有一个“回退队列”的概念,试想如果消费者在消费时发生了异常,那么就不会对这一次消费进行确认(Ack),进而发生回滚消息的操作之后消息始终会放在队列的顶部,然后不断被处理和回滚,导致队列陷入死循环。为了解决这个问题,可以为每个队列设置一个回退队列,它和死信队列都是为异常的处理提供的一种机制保障。实际情况下,回退队列的角色可以由死信队列和重试队列来扮演。

  • 重试队列

重试队列其实可以看成是一种回退队列,具体指消费端消费消息失败时,为防止消息无故丢失而重新将消息回滚到Broker中。与回退队列不同的是重试队列一般分成多个重试等级,每个重试等级一般也会设置重新投递延时,重试次数越多投递延时就越大。举个例子:消息第一次消费失败入重试队列Q1,Q1的重新投递延迟为5s,在5s过后重新投递该消息;如果消息再次消费失败则入重试队列Q2,Q2的重新投递延迟为10s,在10s过后再次投递该消息。以此类推,重试越多次重新投递的时间就越久,为此需要设置一个上限,超过投递次数就入死信队列。重试队列与延迟队列有相同的地方,都是需要设置延迟级别,它们彼此的区别是:延迟队列动作由内部触发,重试队列动作由外部消费端触发;延迟队列作用一次,而重试队列的作用范围会向后传递。

  • 消费模式

消费模式分为推(push)模式和拉(pull)模式。推模式是指由Broker主动推送消息至消费端,实时性较好,不过需要一定的流制机制来确保服务端推送过来的消息不会压垮消费端。而拉模式是指消费端主动向Broker端请求拉取(一般是定时或者定量)消息,实时性较推模式差,但是可以根据自身的处理能力而控制拉取的消息量。

  • 广播消费

消息一般有两种传递模式:点对点(P2P,Point-to-Point)模式和发布/订阅(Pub/Sub)模式。对于点对点的模式而言,消息被消费以后,队列中不会再存储,所以消息消费者不可能消费到已经被消费的消息。虽然队列可以支持多个消费者,但是一条消息只会被一个消费者消费。发布订阅模式定义了如何向一个内容节点发布和订阅消息,这个内容节点称为主题(topic),主题可以认为是消息传递的中介,消息发布者将消息发布到某个主题,而消息订阅者则从主题中订阅消息。主题使得消息的订阅者与消息的发布者互相保持独立,不需要进行接触即可保证消息的传递,发布/订阅模式在消息的一对多广播时采用。RabbitMQ是一种典型的点对点模式,而Kafka是一种典型的发布订阅模式。但是RabbitMQ中可以通过设置交换器类型来实现发布订阅模式而达到广播消费的效果,Kafka中也能以点对点的形式消费,你完全可以把其消费组(consumer group)的概念看成是队列的概念。不过对比来说,Kafka中因为有了消息回溯功能的存在,对于广播消费的力度支持比RabbitMQ的要强。

  • 消息回溯

一般消息在消费完成之后就被处理了,之后再也不能消费到该条消息。消息回溯正好相反,是指消息在消费完成之后,还能消费到之前被消费掉的消息。对于消息而言,经常面临的问题是“消息丢失”,至于是真正由于消息中间件的缺陷丢失还是由于使用方的误用而丢失一般很难追查,如果消息中间件本身具备消息回溯功能的话,可以通过回溯消费复现“丢失的”消息进而查出问题的源头之所在。消息回溯的作用远不止与此,比如还有索引恢复、本地缓存重建,有些业务补偿方案也可以采用回溯的方式来实现。

  • 消息堆积+持久化

流量削峰是消息中间件的一个非常重要的功能,而这个功能其实得益于其消息堆积能力。从某种意义上来讲,如果一个消息中间件不具备消息堆积的能力,那么就不能把它看做是一个合格的消息中间件。消息堆积分内存式堆积和磁盘式堆积。RabbitMQ是典型的内存式堆积,但这并非绝对,在某些条件触发后会有换页动作来将内存中的消息换页到磁盘(换页动作会影响吞吐),或者直接使用惰性队列来将消息直接持久化至磁盘中。Kafka是一种典型的磁盘式堆积,所有的消息都存储在磁盘中。一般来说,磁盘的容量会比内存的容量要大得多,对于磁盘式的堆积其堆积能力就是整个磁盘的大小。从另外一个角度讲,消息堆积也为消息中间件提供了冗余存储的功能。援引纽约时报的案例( https://www.confluent.io/blog/publishing-apache-kafka-new-york-times/),其直接将Kafka用作存储系统。

  • 消息追踪

对于分布式架构系统中的链路追踪(trace)而言,大家一定不会陌生。对于消息中间件而言,消息的链路追踪(以下简称消息追踪)同样重要。对于消息追踪最通俗的理解就是要知道消息从哪来,存在哪里以及发往哪里去。基于此功能下,我们可以对发送或者消费完的消息进行链路追踪服务,进而可以进行问题的快速定位与排查。

  • 消息过滤

消息过滤是指按照既定的过滤规则为下游用户提供指定类别的消息。就以kafka而言,完全可以将不同类别的消息发送至不同的topic中,由此可以实现某种意义的消息过滤,或者Kafka还可以根据分区对同一个topic中的消息进行分类。不过更加严格意义上的消息过滤应该是对既定的消息采取一定的方式按照一定的过滤规则进行过滤。同样以Kafka为例,可以通过客户端提供的ConsumerInterceptor接口或者Kafka Stream的filter功能进行消息过滤。

  • 多租户

也可以称为多重租赁技术,是一种软件架构技术,主要用来实现多用户的环境下公用相同的系统或程序组件,并且仍可以确保各用户间数据的隔离性。RabbitMQ就能够支持多租户技术,每一个租户表示为一个vhost,其本质上是一个独立的小型RabbitMQ服务器,又有自己独立的队列、交换器及绑定关系等,并且它拥有自己独立的权限。vhost就像是物理机中的虚拟机一样,它们在各个实例间提供逻辑上的分离,为不同程序安全保密地允许数据,它既能将同一个RabbitMQ中的众多客户区分开,又可以避免队列和交换器等命名冲突。

  • 多协议支持

消息是信息的载体,为了让生产者和消费者都能理解所承载的信息(生产者需要知道如何构造消息,消费者需要知道如何解析消息),它们就需要按照一种统一的格式描述消息,这种统一的格式称之为消息协议。有效的消息一定具有某种格式,而没有格式的消息是没有意义的。一般消息层面的协议有AMQP、MQTT、STOMP、XMPP等(消息领域中的JMS更多的是一个规范而不是一个协议),支持的协议越多其应用范围就会越广,通用性越强,比如RabbitMQ能够支持MQTT协议就让其在物联网应用中获得一席之地。还有的消息中间件是基于其本身的私有协议运转的,典型的如Kafka。

  • 跨语言支持

对很多公司而言,其技术栈体系中会有多种编程语言,如C/C++、JAVA、Go、PHP等,消息中间件本身具备应用解耦的特性,如果能够进一步的支持多客户端语言,那么就可以将此特性的效能扩大。跨语言的支持力度也可以从侧面反映出一个消息中间件的流行程度。

  • 流量控制

流量控制(flow control)针对的是发送方和接收方速度不匹配的问题,提供一种速度匹配服务抑制发送速率使接收方应用程序的读取速率与之相适应。通常的流控方法有Stop-and-wait、滑动窗口以及令牌桶等。

  • 消息顺序性

顾名思义,消息顺序性是指保证消息有序。这个功能有个很常见的应用场景就是CDC(Change Data Chapture),以MySQL为例,如果其传输的binlog的顺序出错,比如原本是先对一条数据加1,然后再乘以2,发送错序之后就变成了先乘以2后加1了,造成了数据不一致。

  • 安全机制

在Kafka 0.9版本之后就开始增加了身份认证和权限控制两种安全机制。身份认证是指客户端与服务端连接进行身份认证,包括客户端与Broker之间、Broker与Broker之间、Broker与ZooKeeper之间的连接认证,目前支持SSL、SASL等认证机制。权限控制是指对客户端的读写操作进行权限控制,包括对消息或Kafka集群操作权限控制。权限控制是可插拔的,并支持与外部的授权服务进行集成。对于RabbitMQ而言,其同样提供身份认证(TLS/SSL、SASL)和权限控制(读写操作)的安全机制。

  • 消息幂等性

对于确保消息在生产者和消费者之间进行传输而言一般有三种传输保障(delivery guarantee):At most once,至多一次,消息可能丢失,但绝不会重复传输;At least once,至少一次,消息绝不会丢,但是可能会重复;Exactly once,精确一次,每条消息肯定会被传输一次且仅一次。对于大多数消息中间件而言,一般只提供At most once和At least once两种传输保障,对于第三种一般很难做到,由此消息幂等性也很难保证。

Kafka自0.11版本开始引入了幂等性和事务,Kafka的幂等性是指单个生产者对于单分区单会话的幂等,而事务可以保证原子性地写入到多个分区,即写入到多个分区的消息要么全部成功,要么全部回滚,这两个功能加起来可以让Kafka具备EOS(Exactly Once Semantic)的能力。

不过如果要考虑全局的幂等,还需要与从上下游方面综合考虑,即关联业务层面,幂等处理本身也是业务层面所需要考虑的重要议题。以下游消费者层面为例,有可能消费者消费完一条消息之后没有来得及确认消息就发生异常,等到恢复之后又得重新消费原来消费过的那条消息,那么这种类型的消息幂等是无法有消息中间件层面来保证的。如果要保证全局的幂等,需要引入更多的外部资源来保证,比如以订单号作为唯一性标识,并且在下游设置一个去重表。

  • 事务性消息

事务本身是一个并不陌生的词汇,事务是由事务开始(Begin Transaction)和事务结束(End Transaction)之间执行的全体操作组成。支持事务的消息中间件并不在少数,Kafka和RabbitMQ都支持,不过此两者的事务是指生产者发生消息的事务,要么发送成功,要么发送失败。消息中间件可以作为用来实现分布式事务的一种手段,但其本身并不提供全局分布式事务的功能。

下表是对Kafka与RabbitMQ功能的总结性对比及补充说明。

功能项Kafka**(1.1.0版本)**RabbitMQ**(3.6.10版本)**
优先级队列不支持支持。建议优先级大小设置在0-10之间。
延迟队列不支持支持
死信队列不支持支持
重试队列不支持不支持。RabbitMQ中可以参考延迟队列实现一个重试队列,二次封装比较简单。如果要在Kafka中实现重试队列,首先得实现延迟队列的功能,相对比较复杂。
消费模式推模式推模式+拉模式
广播消费支持。Kafka对于广播消费的支持相对而言更加正统。支持,但力度较Kafka弱。
消息回溯支持。Kafka支持按照offset和timestamp两种维度进行消息回溯。不支持。RabbitMQ中消息一旦被确认消费就会被标记删除。
消息堆积支持支持。一般情况下,内存堆积达到特定阈值时会影响其性能,但这不是绝对的。如果考虑到吞吐这因素,Kafka的堆积效率比RabbitMQ总体上要高很多。
持久化支持支持
消息追踪不支持。消息追踪可以通过外部系统来支持,但是支持粒度没有内置的细腻。支持。RabbitMQ中可以采用Firehose或者rabbitmq_tracing插件实现。不过开启rabbitmq_tracing插件件会大幅影响性能,不建议生产环境开启,反倒是可以使用Firehose与外部链路系统结合提供高细腻度的消息追踪支持。
消息过滤客户端级别的支持不支持。但是二次封装一下也非常简单。
多租户不支持支持
多协议支持只支持定义协议,目前几个主流版本间存在兼容性问题。RabbitMQ本身就是AMQP协议的实现,同时支持MQTT、STOMP等协议。
跨语言支持采用Scala和Java编写,支持多种语言的客户端。采用Erlang编写,支持多种语言的客户端。
流量控制支持client和user级别,通过主动设置可将流控作用于生产者或消费者。RabbitMQ的流控基于Credit-Based算法,是内部被动触发的保护机制,作用于生产者层面。
消息顺序性支持单分区(partition)级别的顺序性。顺序性的条件比较苛刻,需要单线程发送、单线程消费并且不采用延迟队列、优先级队列等一些高级功能,从某种意义上来说不算支持顺序性。
安全机制(TLS/SSL、SASL)身份认证和(读写)权限控制与Kafka相似
幂等性支持单个生产者单分区单会话的幂等性。不支持
事务性消息支持支持

2. 性能

功能维度是消息中间件选型中的一个重要的参考维度,但这并不是唯一的维度。有时候性能比功能还要重要,况且性能和功能很多时候是相悖的,鱼和熊掌不可兼得,Kafka在开启幂等、事务功能的时候会使其性能降低,RabbitMQ在开启rabbitmq_tracing插件的时候也会极大的影响其性能。消息中间件的性能一般是指其吞吐量,虽然从功能维度上来说,RabbitMQ的优势要大于Kafka,但是Kafka的吞吐量要比RabbitMQ高出1至2个数量级,一般RabbitMQ的单机QPS在万级别之内,而Kafka的单机QPS可以维持在十万级别,甚至可以达到百万级。

消息中间件的吞吐量始终会受到硬件层面的限制。就以网卡带宽为例,如果单机单网卡的带宽为1Gbps,如果要达到百万级的吞吐,那么消息体大小不得超过(1Gb/8)/100W,即约等于134B,换句话说如果消息体大小超过134B,那么就不可能达到百万级别的吞吐。这种计算方式同样可以适用于内存和磁盘。

时延作为性能维度的一个重要指标,却往往在消息中间件领域所被忽视,因为一般使用消息中间件的场景对时效性的要求并不是很高,如果要求时效性完全可以采用RPC的方式实现。消息中间件具备消息堆积的能力,消息堆积越大也就意味着端到端的时延也就越长,与此同时延时队列也是某些消息中间件的一大特色。那么为什么还要关注消息中间件的时延问题呢?消息中间件能够解耦系统,对于一个时延较低的消息中间件而言,它可以让上游生产者发送消息之后可以迅速的返回,也可以让消费者更加快速的获取到消息,在没有堆积的情况下可以让整体上下游的应用之间的级联动作更加高效,虽然不建议在时效性很高的场景下使用消息中间件,但是如果所使用的消息中间件的时延方面比较优秀,那么对于整体系统的性能将会是一个不小的提升。

3. 可靠性+可用性

消息丢失是使用消息中间件时所不得不面对的一个同点,其背后消息可靠性也是衡量消息中间件好坏的一个关键因素。尤其是在金融支付领域,消息可靠性尤为重要。然而说到可靠性必然要说到可用性,注意这两者之间的区别,消息中间件的可靠性是指对消息不丢失的保障程度;而消息中间件的可用性是指无故障运行的时间百分比,通常用几个9来衡量。

从狭义的角度来说,分布式系统架构是一致性协议理论的应用实现,对于消息可靠性和可用性而言也可以追溯到消息中间件背后的一致性协议。对于Kafka而言,其采用的是类似PacificA的一致性协议,通过ISR(In-Sync-Replica)来保证多副本之间的同步,并且支持强一致性语义(通过acks实现)。对应的RabbitMQ是通过镜像环形队列实现多副本及强一致性语义的。多副本可以保证在master节点宕机异常之后可以提升slave作为新的master而继续提供服务来保障可用性。Kafka设计之初是为日志处理而生,给人们留下了数据可靠性要求不要的不良印象,但是随着版本的升级优化,其可靠性得到极大的增强,详细可以参考KIP101。就目前而言,在金融支付领域使用RabbitMQ居多,而在日志处理、大数据等方面Kafka使用居多,随着RabbitMQ性能的不断提升和Kafka可靠性的进一步增强,相信彼此都能在以前不擅长的领域分得一杯羹。

同步刷盘是增强一个组件可靠性的有效方式,消息中间件也不例外,Kafka和RabbitMQ都可以支持同步刷盘,但是笔者对同步刷盘有一定的疑问:绝大多数情景下,一个组件的可靠性不应该由同步刷盘这种极其损耗性能的操作来保障,而是采用多副本的机制来保证。

这里还要提及的一个方面是扩展能力,这里我狭隘地将此归纳到可用性这一维度,消息中间件的扩展能力能够增强其用可用能力及范围,比如前面提到的RabbitMQ支持多种消息协议,这个就是基于其插件化的扩展实现。还有从集群部署上来讲,归功于Kafka的水平扩展能力,其基本上可以达到线性容量提升的水平,在LinkedIn实践介绍中就提及了有部署超过千台设备的Kafka集群。

5. 运维管理

在消息中间件的使用过程中难免会出现各式各样的异常情况,有客户端的,也有服务端的,那么怎样及时有效的进行监测及修复。业务线流量有峰值又低谷,尤其是电商领域,那么怎样前进行有效的容量评估,尤其是大促期间?脚踢电源、网线被挖等事件层出不穷,如何有效的做好异地多活?这些都离不开消息中间件的衍生产品——运维管理。

运维管理也可以进行进一步的细分,比如:申请、审核、监控、告警、管理、容灾、部署等。

申请、审核很好理解,在源头对资源进行管控,既可以进行有效校正应用方的使用规范,配和监控也可以做好流量统计与流量评估工作,一般申请、审核与公司内部系统交融性较大,不适合使用开源类的产品。

监控、告警也比较好理解,对消息中间件的使用进行全方位的监控,即可以为系统提供基准数据,也可以在检测到异常的情况配合告警,以便运维、开发人员的迅速介入。除了一般的监控项(比如硬件、GC等)之外,对于消息中间件还需要关注端到端时延、消息审计、消息堆积等方面。对于RabbitMQ而言,最正统的监控管理工具莫过于rabbitmq_management插件了,但是社区内还有AppDynamics, Collectd, DataDog, Ganglia, Munin, Nagios, New Relic, Prometheus, Zenoss等多种优秀的产品。Kafka在此方面也毫不逊色,比如:Kafka Manager, Kafka Monitor, Kafka Offset Monitor, Burrow, Chaperone, Confluent Control Center等产品,尤其是Cruise还可以提供自动化运维的功能。

不管是扩容、降级、版本升级、集群节点部署、还是故障处理都离不开管理工具的应用,一个配套完备的管理工具集可以在遇到变更时做到事半功倍。故障可大可小,一般是一些应用异常,也可以是机器掉电、网络异常、磁盘损坏等单机故障,这些故障单机房内的多副本足以应付。如果是机房故障就要涉及异地容灾了,关键点在于如何有效的进行数据复制,对于Kafka而言,可以参考MirrorMarker、uReplicator等产品,而RabbitMQ可以参考Federation和Shovel。

6. 社区力度及生态发展

对于目前流行的编程语言而言,如Java、Python,如果你在使用过程中遇到了一些异常,基本上可以通过搜索引擎的帮助来得到解决,因为一个产品用的人越多,踩过的坑也就越多,对应的解决方案也就越多。对于消息中间件也同样适用,如果你选择了一种“生僻”的消息中间件,可能在某些方面运用的得心应手,但是版本更新缓慢、遇到棘手问题也难以得到社区的支持而越陷越深;相反如果你选择了一种“流行”的消息中间件,其更新力度大,不仅可以迅速的弥补之前的不足,而且也能顺应技术的快速发展来变更一些新的功能,这样可以让你以“站在巨人的肩膀上”。在运维管理维度我们提及了Kafka和RabbitMQ都有一系列开源的监控管理产品,这些正是得益于其社区及生态的迅猛发展。


四、消息中间件选型误区探讨

在进行消息中间件选型之前可以先问自己一个问题:是否真的需要一个消息中间件?在搞清楚这个问题之后,还可以继续问自己一个问题:是否需要自己维护一套消息中间件?很多初创型公司为了节省成本会选择直接购买消息中间件有关的云服务,自己只需要关注收发消息即可,其余的都可以外包出去。

很多人面对消息中间件时会有一种自研的冲动,你完全可以对Java中的ArrayBlockingQueue做一个简单的封装,你也可以基于文件、数据库、Redis等底层存储封装而形成一个消息中间件。消息中间件做为一个基础组件并没有想象中的那么简单,其背后还需要配套的管理运维整个生态的产品集。自研还有会交接问题,如果文档不齐全、运作不规范将会带给新人噩梦般的体验。是否真的有自研的必要?如果不是KPI的压迫可以先考虑下这2个问题:1. 目前市面上的消息中间件是否都真的无法满足目前业务需求? 2. 团队是否有足够的能力、人力、财力、精力来支持自研?

很多人在做消息中间件选型时会参考网络上的很多对比类的文章,但是其专业性、严谨性、以及其政治立场问题都有待考证,需要带着怀疑的态度去审视这些文章。比如有些文章会在没有任何限定条件及场景的情况下直接定义某款消息中间件最好,还有些文章没有指明消息中间件版本及测试环境就来做功能和性能对比分析,诸如此类的文章都可以唾弃之。

消息中间件犹如小马过河,选择合适的才最重要,这需要贴合自身的业务需求,技术服务于业务,大体上可以根据上一节所提及的功能、性能等6个维度来一一进行筛选。更深层次的抉择在于你能否掌握其魂,笔者鄙见:RabbitMQ在于routing,而Kafka在于streaming,了解其根本对于自己能够对症下药选择到合适的消息中间件尤为重要。

消息中间件选型切忌一味的追求性能或者功能,性能可以优化,功能可以二次开发。如果要在功能和性能方面做一个抉择的话,那么首选性能,因为总体上来说性能优化的空间没有功能扩展的空间大。然而对于长期发展而言,生态又比性能以及功能都要重要。

很多时候,对于可靠性方面也容易存在一个误区:想要找到一个产品来保证消息的绝对可靠,很不幸的是这世界上没有绝对的东西,只能说尽量趋于完美。想要尽可能的保障消息的可靠性也并非单单只靠消息中间件本身,还要依赖于上下游,需要从生产端、服务端和消费端这3个维度去努力保证,《 RabbitMQ消息可靠性分析》这篇文章就从这3个维度去分析了RabbitMQ的可靠性。

消息中间件选型还有一个考量标准就是尽量贴合团队自身的技术栈体系,虽然说没有蹩脚的消息中间件只有蹩脚的程序员,但是让一个C栈的团队去深挖PhxQueue总比去深挖Scala编写的Kafka要容易的多。


五、总结

消息中间件大道至简:一发一存一消费,没有最好的消息中间件,只有最合适的消息中间件。人过留名,雁过留声,路过记得点个赞。


从原理到策略算法再到架构产品看推荐系统 | 附Spark实践案例

$
0
0

作者 | HCY崇远


01 前言

本文源自于前阵子连续更新的推荐系统系列,前段时间给朋友整理一个关于推荐系统相关的知识教学体系,刚好自身业务中,预计明年初随着业务规模增长,估摸着又要启动推荐相关的项目了,所以也是趁机把相关的知识结构梳理了一遍。这这里重新做整理,并额外做了一些增减,让整体逻辑会更通顺一点。


整个文章的结构逻辑,先从推荐系统的基础知识结构讲起,然后由浅入深过渡到几个推荐策略算法上,并且为每个推荐策略算法提供一些简单的入门Spark案例代码,再从策略过渡到系统层级,包括数据架构、策略组合、效果评估等,最终再从上层产品设计的角度去补充整个系统知识结构。


整体来看,通篇并没有涉及到特别高深的推荐算法(部分专门讲这部分的文章,只有有一定基础的朋友才更容易接受,本文章的逻辑略有不同),大多都是常规的策略模型,核心在于对整个推荐系统的知识结构进行解构,让那些对于推荐系统感兴趣的朋友能快速的建立起对于推荐系统的知识体系结构,甚至能够通过文章中的算法案例,做简单的实践,从而达到快速入门的目的。


系列拆分阅读:

《推01,你们是不是都觉得自己少了个推荐系统?》

《推02,就算非技术人员也有必要了解的推荐系统常识》

《推03,最最最简单的推荐系统是什么样的 | 附Spark实践案例》

《推04,融合了用户兴趣的推荐系统才会更具个性 | 附Spark实践案例 》

《推05,论推荐系统之经典,还得数协同 | 附Spark实践案例》

《推06,从推荐策略算法到推荐系统,到数据架构,再到产品设计》


关于我:

大数据行业半个老鸟,我家梓尘兄的超级小弟,会敲代码、会写文章,还会泡奶粉哄小屁孩。

想和我交流的,可以加我个人微信mute88,可以拉你入交流群,但请注明身份and来意~

关于代码和案例,可以做付费咨询。


友情提示:据不完全统计,包含代码片,通篇大约接近1万字,预计阅读时间?我也不知道,哈哈,可以当成短篇小说来读了。


02 推荐系统场景需求


本章节从场景的需求出发,试图来分析推荐系统需求的必须性,以及很多平台言必谈个性化推荐的现状。


0.2.1 先从人工智能话题出发


说推荐系统之前先掰掰人工智能,这个词估计大家能能听得懂,毕竟是风口上的名词,想没听过也难。那么问题来了,你觉得推荐系统与人工智能有什么关系?


或许大半的人会认为没有半毛钱的关系,这让我想到了前几天周末在知乎上怼的一个问题,问题的核心就是:“现在大数据都很low了,大家都是去搞人智能了”。


这典型就是对于人工智能定义认知的问题,个人认为人工智能就是一个偏业务的定义,多维度多学科交叉的概念,压根儿就不好以技术维度去对比去评判。其核心的三要素就是:算法、计算能力以及数据。


围绕大量的基础数据,对基础数据进行特征处理,然后构建有用的业务算法模型,然后基于分布式的基础架构计算能力,将算法模型的用于实际的生产环境,以机器替代人工的作业,以提升效果与效率,达到机器智能化的目标。


那再回到推荐系统的话题,在过去传统的门户网站或者其他领域,也是有推荐场景的,不过大部分都是基于编辑或者运营手动进行配置推送,随着对数据、对算法模型的进一步应用,才逐渐有算法机器替代人工进行推荐,并且达到诸如“千人千面”、“个性化”推荐的效果。


所以,追究其本质,其实也是算法模型+计算过程+基础数据的流程,并且最终达到了机器自动化、智能化的效果,从广义的角度来说,或许复杂一些的推荐系统或许也能纳入人工智能的范畴了(真心怕那种一说到人工智能=神经网络的选手)。


0.2.2 推荐与检索两种信息获取的方式


说到推荐系统,就不得不说一下搜索引擎。不管是搜索也好、推荐也好,他们都是信息获取的一种机制,核心区别在于主动与被动。


搜索引擎是典型的主动触发的形态,即用户已经有明确的信息获取意图,渴望得到自身既定的目标信息,让后通过搜索规则进行最终信息的获取。


比如,你好奇什么是人工智能,那么你就会用诸如谷歌、或者国产大百度去搜索,然后获取到相关网页,去点击查看,最终完成你了解人工智能这个信息获取的目的。这就是检索的机制,你先要告诉系统你的意图,然后在给你筛选你要的信息。


而推荐系统则大大的不同,它是一种系统主动的行为,对于用户来说是一个被动的行为,被动的接受系统推送过来的信息。那这样强扭是不是很尴尬呢?怎么有这么SHA叉的机制?


其实不是的,尴尬的是推的不对,东西推对了就尴尬了,比如你正在浏览一个信息,正在愁这个信息还没解决你的问题的时候,系统啪丢给你几个新增的信息,说这个几个信息可能能解决的问题,你一看我凑,这正是我要的,感谢万能的推荐系统!


所以,推荐核心解决的还是用户额外信息获取的问题,以及提升用户的进一步转化,停留时间的延长(只要停留时间延长,商业转化机会就会加大,也是粘性提升的体现),而问题的核心就是要推的准,推的恰到好处,不然就是反作用。


因为推荐要解决的就是海量信息冗余,用户在目的不算很明确的情况,进一步帮助其确定目标,主动筛选信息的过程,推的不好那对于用户来说就更冗余了。


关于信息的获取,其实还有一种常见的形态,那就是结构化导航,比如电商平台的分门别类罗列,门户网站的结构化频道信息。它是通过把信息进行结构化了,构建脉络结构,帮助你去获取你要的信息。不过,这个就不在我们的讨论范围内了。


0.2.3 推荐系统的场景


说了这么多篇逻辑理论的东西,或许很多朋友依然对推荐系统没有一个很场景化的认知,比如具体什么场景?具体什么形态?

这是我在腾讯视频上截的图,这就是典型的视频推荐场景,我不是鹅厂腾讯视频业务的算法工程师,所以我无法回答你他们的推荐机制,但我可以告诉你,当时我的观看主体是“地球脉动”,结合推荐列表,大伙儿可以揣摩一下他的推荐机制。当前观看的属性相关?导演关联性?我的观看记录偏好?从我个人的评估来看,这些因素应该都有。


顺带说一下的就是,一个完整的好的推荐系统,一定不会单纯的依赖于某个推荐算法,虽然这个系列的后面文章中,我会讲一些推荐机制或者算法逻辑,甚至附上简单的案例代码,但还是要提前说一下这个问题。


我们再来看几个同样是腾讯系的产品推荐场景:

QQ音乐平台的推荐,分析来看应该跟我当前主页音乐的风格、以及我的历史浏览相关。

这是阅文网站的小说小说推荐,即当你浏览一本小说时,下面会给这个推荐列表,从其描述以及个人分析来看,好像与个人的行为相关性会小一些,应该是基于大盘用户的浏览轨迹做的关联分析,进而进行关联推荐。

最后是电商平台的典型案例,即你在浏览商品时,一般都有猜你喜欢模块,并且推荐系统得以大放光彩,成为应用领域里典型的应用场景,还是得益于亚马逊。当年亚马逊使用推荐算法帮助其提升了XX(具体多少忘了)的年度利润,从此一炮而红,基本上电商平台中的推荐系统就成了标配。


0.2.4 推荐系统的一些坑


看了这么多例子,再结合自己身边实际的体验,确实不难发现,各色各样的产品、平台,都在打造自己的推荐产品,恨不得用户一直点下去,永不跳出。鉴于这种情况,那些尚未为自己产品或者平台开发推荐逻辑的,是不是感觉自己少了个推荐系统,哈哈。


其实核心还是那句话,推荐本身就是个双刃剑,用的不好只会让用户徒增烦恼,这里所说的好不好,不单纯是说准不准的问题,准是前提,即推荐给用户切身所需肯定是好的,但这还不够,你还需要在他需要的时候给他推,时机不对、场景不对,即使你推的东西再准,那也是瞎比推。


所以,即使你觉得你少了个推荐系统,也是需要慎重,或许跟完这个系列会好点?正如上面说的,一些坑还是需要注意的。上面所说的推荐时机以及场景就不再重复了。


第一,好的推荐系统一般情况下很依赖于用户的行为数据,因为从用户行为中自然能一窥用户的一些偏好所在,但实际情况是,用户的行为数据并不是这么容易的,当用户行为数据不够的时候,基于用户行为的分析结论就是个伪命题,甚至会把你带向错误的方向。


第二,用户的偏好一定是会时间偏移进行转变的,所以用户行为的有效性又会是一个问题。


第三,假设这个是新用户呢?完全没有轨迹信息,怎么破。


第四,实际影响用户的选择的因素太多,我们容易陷入主观臆断的误区,综合性考虑是一个完善推荐系统的必须思考的地方。


第五,产品层面的逻辑有时候比底层算法更有效,典型如上面阅文的截图例子,“喜欢这本书的人也喜欢”,这就是一种策略,也是一种推荐解释,可解释性会提升推荐的可信度,诸如还有一些交互方式、产品形态都是对推荐转化有影响的。


03 推荐系统的基础知识


基于上面章节的内容,我们对于推荐系统的常见场景有了一个大概的认知,这个章节,我们从推荐系统本身的基础知识进行拆解,帮我们从理论上掌握更多关于推荐系统相关的知识。


0.3.1 推荐系统概述


在上个章节,我们也大致的提到过,需要先明确的一点就是推荐算法或者推荐机制并不严格等同推荐系统,推荐系统是一个相对复杂的业务系统,里头涉及到数据的处理、架构的构成、推荐的逻辑机制,反馈数据的回收、效果的跟踪、AB测试等等。


并且,很多我们耳熟能详的推荐算法,他只是解决的某种特定情况下的推荐机制问题,而整个系统很多时候是复合了多种算法结果,综合呈现的一种结果。但可以肯定的是,各种理论逻辑、算法机制是构建推荐系统的核心支撑,所以,学习推荐系统,首先学习各种推荐算法并没有毛病。


推荐算法概述-基于内容属性相似的推荐


从原始数据依赖的层面来说,常见的有基于内容属性的推荐机制,这种推荐逻辑很简单,只是单纯的依赖物品之间的属性相似来构建推荐关系,容易理解,有时间还是有一定效果的,但实际上很多时候会存在这几种情况,导致了这种原始推荐失效。


  • 如果用户浏览当前的物品本身就不是用户的菜,甚至是一个非优质信息(当前主体不可控),再基于当前物品进行推荐就是个伪命题。

  • 基于上面这条,即使当前主体是用户的目标,但再推类似主体会造成信息冗余,即当前主体信息已经解决了用户的问题。


所以,由于用户行为的不可控,基于内容属性相似的推荐,风险还是挺高的,这是导致了这种原始直接的机制并不会得到广泛的推广。但与乱推荐相比,还是有一定正向作用的,毕竟用户浏览的主体是自身选择的结果,本身用户对于其选择的信息主体是有一定偏好性的。


推荐算法概述-基于用户画像的推荐


基于物品本身属性的推荐,其实与个性化是没有半毛钱的关系的,毕竟推荐候选集只跟物品主体有关,与用户无关,就谈不上什么个性化了。


而基于用户画像(更多人喜欢用基于用户标签)的推荐,则更大程度上依赖于用户的画像属性来推荐,这就体现了用户偏好信息,根据偏好信息来选择候选集。


这是一种很通用的做法,并且在大规模数据集情况下,很多实际的产生过程中喜欢使用这种机制。而用户的画像,或者更具体点用户的兴趣标签如何构建呢?其实就是依赖用户累积的行为数据了,通过行为数据生成用户的兴趣标签。


这看似是一种相对靠谱的做法,毕竟如果把用户的爱好都分析清楚了,主动给用户做推荐不就显得很个性化了吗?在实际的场景中,首先,并不是所有用户的行为都足够用来表征其兴趣偏好的,即我们会高估用户的行为集合,从而产生有偏差的画像属性,更甚者,如果用户完全没有行为怎么办呢?


其次,通常来说,用户的兴趣爱好是会随时间迁移而改变的,所以,把我用户的兴趣程度以及其变化并不是一个容易的事情,更何况用户实际的选择还会受很多因素影响,比如,我当前查找的一个信息并不是我之前掌握的信息,那意味着这些信息偏好在我的历史轨迹中都体现不出来,那单纯的通过我的兴趣去推荐就显得不靠谱了。


但不管怎么说,根据用户的偏好来做推荐,大方向肯定是没有问题的。


推荐算法概述-基于协同过滤的推荐


协同过滤,或许了解过推荐系统的的朋友,多多少少都能听过一些,并且协同推荐可是作为推荐领域典型案例的存在。


协同过滤同样不会去研究物品的本身属性,甚至也没有空去构建用户的画像标签,正如他的名字描述的一样,他严重依靠于用户的行为以及其周边用户的协同行为。举个例子,为一个用户推荐信息,那么我只需要参考其周边用户在看什么信息,就给他推荐什么信息就好了。


重点在于,如何限定周边这个范围,比如根据两个用户的行为,去构建相关关系,从而判断用户之间的相似程度,把相似用户的行为推荐给当前用户,这就是协同中典型的基于用户推荐。


而如果以物品为维度,以用户的购买或者观看记录为向量,则可以构建物品的相似度量,针对于每一个待推荐选项,用户的历史轨迹就是其向量构成,就可以判断该用户历史的轨迹信息与当前的待选物品的向量相关度了,从而判断是否要推荐,这就是基于物品的协同逻辑。


与基于用户画像的推荐对比,这种推荐有一定几率可以发现新物品,即并不严格依赖用户的兴趣。举个例子,假设几个信息的层级是ABC,并且ABC是层级递进关系,并不是同一个东西,对于一个用户来说,他掌握的是A,则意味着他的兴趣偏好大多偏向于A,根据兴趣标签,其实是很难推荐这种递进相关的信息。


但是,如果其他用户的学习轨迹都是A->B->C这种轨迹,这意味着ABC三者之间本身就有前后潜在逻辑关系存在的,基于协同,即可为该用户在掌握A的基础上,推荐BC的内容,这也是基于兴趣所做不到的地方。


当前,基于协同行为的推荐,除了基于物品还有基于用户,还有其他诸如基于模型的协同,典型如最近邻模型、基于矩阵分解、以及基于图关系模型的构建的推荐机制。


推荐算法概述-其他


其实在我们实际的操作过程中,并不会严格的依赖于这种条条框框、只要合理即可行,比如我们完全可以把推荐问题转化为分类问题,针对于每个待选项,他都是YES OR NO的问题,即一个二值分类。


又比如在上一篇我们学习的一个场景,即阅文网站的小说推荐,还记得他的推荐标题吗?“喜欢这本书的人还喜欢”,这就是典型的“啤酒与尿布”的解法,即货架思维,关联销售,也是可以作为一种推荐机制而存在的。


在比如微信朋友圈,微信一定是会研究用户的朋友圈关系的,比如你对哪类朋友点赞、互动行为最多,它是不是会考虑推荐你欣赏的朋友偏好内容给你?毕竟微信是一个典型的熟人社交模型。


所以,推荐算法看似重要,但其实想想又没有这么重要,很多时候并不是一成不变的,都要我们根据场景去考虑,最最最重要的是,需要我们用实际效果来选择机制,也或许是多种机制共同生效的结果。


0.3.2 相似度量


在我们上面的推荐算法机制中,有个不得不提的操作处理就是各种相似相关度的计算,我们来简单分享一下几种相似或者相关度量的方式。


欧几里得距离(Euclidean Distance)


最常见的距离度量方式,衡量多维空间中两点之间的绝对距离,要求维度的统一。


明可夫斯基距离(Minkowski Distance)


明氏距离是欧氏距离的扩展,是对多个距离度量公式的概括性的表述(可以看到,当p=2时,其实就是欧式距离)。


曼哈顿距离(Manhattan Distance)


曼哈顿距离来源于城市区块距离,是将多个维度上的距离进行求和后的结果,即当上面的明氏距离中p=1时得到的距离度量。

//还有其他的一些距离度量,但是都不太常用,最常用的依然是欧式距离度量。


向量空间余弦相似度(Cosine Similarity)


余弦相似度用向量空间中两个向量夹角的余弦值作为衡量两个个体间差异的大小。相比距离度量,余弦相似度更加注重两个向量在方向上的差异,而非距离或长度上。


皮尔森相关系数(Pearson Correlation Coefficient)


即相关分析中的相关系数r,分别对X和Y基于自身总体标准化后计算空间向量的余弦夹角。基于内容的推荐,还有一点需要注意的就是,对于物品自身属性,如果属性值过少,我们需要适当进行扩大维度,如果维度过多,则需要进行降维。


关于降维和升维,都是一个很大的研究方向,大体上可以说一下几种常见的方式。例如降维,我们可以进行维度聚类、主题抽取,进一步把相关维度进行合并,进一步减少维度;而对于升维,我们可以把维度进行矩阵化,例如假设物品X有A和B两个维度属性,那么我们通过生成A*B矩阵的方式,把维度扩充到A*B个维度。


0.3.3 冷启动问题的解决


所谓冷启动,即在推荐系统初期时,没有任何用户与物品的交集信息,即无用户的行为轨迹,无法通过类似协同或者用户偏好等方式进行推荐,这种时候,我们就称推荐系统处于冷启动状态。


这种情况,我们需要尽快的累积起第一批用户行为轨迹。我们可以通过基于内容的推荐,或者做一些其他类似的操作,快速有效的进行物品推荐。一段时间后,累积到一定的用户行为时,整个系统就能够正常使用协同过滤等方式进行推荐了。


但是,针对于新加入的用户,或者新加入的物品,同样也是出于冷启动状态的,这个时候,我们通过需要对这种物品或者用户做特殊的处理。


除了基于内容属性的推荐,我们还有其他的一些策略用于弥补这种行为数据不足的情况,比如典型的热度模型,推荐热点信息这种行为虽然low,但是从整体的反馈来看,还是有一定效果的,此外,还可以根据一些统计学上的结论,进行基于统计分析结论的推荐。


除此之外,我们也可以通过其他渠道收集用户的数据,比如用户注册的时候所填写的个人资料,这些都是可以作为推荐的原始依赖数据。


0.3.4 马太效应


马太效应或者说长尾效应,即热者愈热,实际举例来说就是,在实际的购买场景中,由于你推荐的次数越多,部分优质的商品购买或者点击的次数就越多,形成的用户购买轨迹就越多,所以得到的推荐机会就越多,进而产生的推荐也越多,变得越热。


随着不断迭代,子子孙孙无穷尽也,这样得到推荐的商品就会集中在少部分商品中,而大部分长尾商品是沉寂的,一个推荐系统如果长时间处于长尾效应中,造成推荐疲劳,其推荐效果就会减弱。


所以,一个好的推荐系统,要考虑到适当的挖掘长尾商品,通过真的个性化,把适当的长尾商品送到真正需要他们的人手里,在实际的操作过程中,我们可以适当的进行热度降权,从而让一些中下层的商品得到更多的曝光机会,当然前提是保证点击率的情况下。


另外一个场景会形成马太效应的是热度模型,即我们的热度榜单,长时间的高居榜首,一定会获得更多的点击,而点击越多其热度越高,但我们的信息是需要保持新鲜度的,不然点击率迟早会下架的。


所以,我们使用一些机制让处于头部的商品或者信息降权,时间衰减是一个比较通用的做法,即随着时间的迁移,其整体热度会不断的下降,至于说下降的方式,速率就看模型的设计了。


0.3.5 AB测试


关于推荐的效果,之前我们说过其核心的考核标准就是点击率,点击的越多说明推荐的越准确,用户的停留时长也会越长,只要把用户留在平台中,机会总是会有的。其实就是一层漏斗嘛?这一层的基数越大,下一层转换的量就会越高,这也是推荐系统的核心存在意义。


并且之前也说到过,一个不好的推荐系统有时间反而会形成反向作用,所以,一个推荐系统的迭代更新至关重要。离线的效果评估一定是要做的,最起码在离线实验的阶段需要保证当前的效果优于线上效果,才能进行迭代。


但是,实际情况是复杂的,对于推荐的模型来说,离线的实验其实并没有想象中靠谱,那么,就丢到线上去真多真枪的实验一把,就知道效果了。但是,实际的生产环境中,任何一点转化波动的影响都是极其严重的,谁也不敢拿实际生产开玩笑。


于是,就有了AB测试机制的产生,所谓AB测试机制,即将流量分为AB两类,A流量走原始的旧模型,B流量走新模型,同步测试同步对比,效果一目了然。


当然,在实际的AB测试流程中,首先流量是可以自由分配的,一般情况下新模型在最终确认之前流量一定是少量的,随着模型逐渐被验证,流量比重会逐渐加大,最终确认后流量全部导向新模型,完成新模型的正式上线。


并且,通常,在实际的环境中,或许我们会同时有十多个甚至是几十个新模型在同时实验,每个模型调整的因子都不一样,最终选择最适合的因素进行调整,达到效果最优,这也就是AB测试机制的魅力所在。


所以,打造一个好的AB测试系统,首先流量是需要可控的,其次模型的迭代上线是需要高度灵活的,最后,肯定是需要有完整的数据回收、数据分析对比机制存在的。


04 基于内容属性的推荐策略算法


从这个章节开始,我们将从理论进一步过渡到具体的推荐策略算法,我们先从最简单的基于内容属性相关的策略算法着手。


0.4.1 最简单的推荐机制


如标题,既然是“最最最简单”的推荐系统,其实也不能说是推荐系统,之前也说了,系统是一个复合的完整系统,所以这里说推荐机制可能会更恰当些。结合之前大致陈述的一些推荐机制,最最最简单的推荐机制,无疑是基于主体属性相似或者相关推荐了,连个性化都说不上,铁定最最最简单了。


说到这,说不定有些人不愿意干了,既然如此简陋的推荐机制,不看也罢。BUT,真的不要小看基于内容相似的推荐,存在即合理。我们在进行信息获取时,其实本身就是具有一定识别能力的,这意味着我们最终选择查看的信息都是经过我们大脑大致思考的结论,这意味着这些信息是有参考价值的。


并且,在很多时候,我们是需要同类信息进行我们获取到的信息进行补全的,完善我们对目标信息的获取程度。基于这个考量,基于内容属性的推荐其实是说的过去的。


别不服,我们来上例子,还是以前面文章那个腾讯视频的推荐场景图为例。

图是在使用腾讯视频观看视频时,我亲手截推荐栏位的内容,补充一下背景(很重要,请注意):

1 我当时观看的是应该是《蓝色星球第二季》纪录片

2 我经常在腾讯视频上看的一般是大片,并且一般是国外的

3 由于是VIP账号,梓尘兄也经常用这个账号看动画片,诸如《小猪佩奇》之类的

4 在腾讯视频上,纪录片中,我只看过《地球脉动》和《蓝色星球》,并且,我真不是纪录片的爱好者,只是喜欢这两部而已


基于上面我提供的个人行为数据,再结合看这批推荐列表,不难发现,上面有很多的纪录片,你觉得跟我们当时正在浏览的内容有没有关系?或者你认为我行为记录中很多纪录片的记录?又或者是我是纪录片的狂热者,导致了腾讯视频给我猛推纪录片。


所以,连腾讯视频都会考虑基于当前浏览内容的属性进行推荐(并且是大范围),你还觉得这种做法十分之LOW吗?当然你也可以认为腾讯视频推的不准,瞎J吧推,也是可以的,我也认同,不是非常准(哈哈,《地球脉动》所有我都看过了,还给我瞎推,上面给推的没几个有欲望去点的,给腾讯视频推荐的开发兄弟们打脸了,不好意思)。


我只想表达的是,这种简单的推荐机制,在整个推荐系统中真的是不可缺少的部分,很多时候简单并不代表无效,类似上面这种情况,我可以举出太多有名有姓的实际案例来,说多了没意义,所以,咱继续。


0.4.2 过程并没有这么简单


从直接的推荐机制来看,整个实现流程看着真的很简单,但是在实际的操作过程中,还是有一些东西值得探讨以及注意的。


第一、首先是,相似计算的过程


之前文章有大致提到过,相似或者相关计算还是有很多可以选择的,他们每一种都有各自的特点以及适应性。以相似计算中使用最多的欧式距离与余弦相似为例,专业点的说法就是余弦夹角可以有效规避个体相同认知中不同程度的差异表现,更注重维度之间的差异,而不注重数值上的差异,而欧式距离则是对个体异常数值会比较敏感。


这意味着,在我们需要区分异常样本时,使用距离计算会更恰当,聚个栗子,比如电商领域中高价值与低价值用户的区分,其实我们核心是想把他们的差异性拉大的,得以体现出对比,这个时候使用余弦就是不合理的。


在回归到距离上说,市面上除了欧式距离,还有好几种距离度量,诸如马氏、曼哈顿距离等等,其实其度量侧重都是不一样的,我们需要结合实际的场景去使用。还有更偏向于相关度量的皮尔森相关系数等。


第二、需要解决相似计算中,计算矩阵过大的问题


按照标准流程,假设有1万个物品,则对于每个物品来说,需要与其他物品计算与其的相似度或者相关度,然后再排个序,取TopN形成自身的待推荐列表。那么,简单的数学题来了10000*10000=10000万次计算,这显然是不合理的。


所以,优化这个过程是必然的,关键是如何优化。核心思想其实就是初筛嘛!把那些完全没啥多大鸟关系的直接干掉,省掉计算相似的过程,节省资源。如何筛选?一个比较常见的做法是,寻找核心关键影响因素,保证关键因素的相关性。


比如,在实际的生产操作过程中,很多时候会通过关键属性是否基本匹配作为判断依据,或者直接通过搜索构建进行检索初筛,把大致相关的先过滤一遍,通过这种简单而粗暴的方式,其实已经能把大部分相关度很低的候选集给过滤掉,对于整体计算量级来说,计算复杂度直接下降。


第三、多个因子如何权衡影响权重


基于属性计算相似,从整体上来看,其实一般主体都不止一个属性,那么计算相关的时候到底看那个属性呢?或者说哪些属性应该占有更高的权重,哪些因素是次要因素。


还是以上面的腾讯视频的推荐为例,从结果上来反推相似推荐的部分(当然,实际情况不详哈,只是推断而已),显然当前视频的类别占了很大的权重(记录片),除此之外包括导演啊,一些其他特征属性应该也会参考在内的。


回到常规问题,如何确定影响权重是个操作难题。最简单并且实际上还挺有效的一种方式就是专家评判法,即通过权威经验来划定影响因子的权重,还有就是通过标注的样本进行反向拟合每种因素的占比权重。除此之外还有一些其他学术上的方法,包括什么主成分分析法,层次分析法,还有什么熵权法,其实都是找因子影响能力的主次关系。


最终确定好了影响因素,在实际上线回收到数据之后,依然是需要逐步的进行权重影响调整的,我们可以通过结果的样本数据,进行LR的回归拟合,寻找最合适的权重配比。


0.4.3 最简单的推荐策略算法实践

说了这么多理论,不能光说不练,标题上写着“附Spark案例”,很多人都是冲着这来的呢,前面BB了这么多屁话,还不见代码。来,我们这就上正文。


不过不用期待过多,毕竟这只是一个简单的相似计算的过程而已,所以权当属性实验数据以及Spark开发了,高手可以略过了。


一、实验数据简介


其实看到这三部分数据的简介,一些老手估计已经知道是什么数据了,是的,就是那份有名的电影数据集(MovieLens开放数据),并且取的是完全版的那份,简直成了推荐系统的标配实验数据了。


三个文件,其中电影数据集共1万多个电影基础数据,评分数据集最大共100万条评分数据,以及10万条的用户对电影的打标签数据,总大小约为几百兆,不大,但是用来做实验玩玩那是相当足够了。


二、推荐机制逻辑


我们的核心计算逻辑还是内容属性上的相似嘛,所以核心是看看围绕电影,有哪些属性是可以抽取出来的,并且参与计算的。


第一,电影的类别,基于上面腾讯视频的考虑,其实这个显然很重要,而电影的类别信息存储于电影数据集中,并且是一对多的关系,即一个电影可以对应多个类目,我们需要进行切割,由于计算这个维度相似的时候,是多对多的关系,天然的计算相似或者相关的特征。


第二、电影的播放年份,电影的年份其实有种潜在的关联关系,举个例子可以说明,比如说零几年的电影与现状的电影风格是不同的,当时间跨度有一定差距时,这个还是蛮明显的。关于电影的年份数据,从数据样本可以知道,它隐藏在电影的名字中,写个正则过滤出来即可。至于说如何计算这个维度的相关,我们可以用两者差距来算相关,比如年份绝对值越远,这个值越小,越近甚至是重叠就越大。


第三,电影的标签,电影本身是没有标签属性的,但它有用户对他打的标签信息,所以我们需要进一步处理,把它变成电影的属性,需要清洗、规整以及处理。标签本身也是多对多的关系,同样可以计算相似度,比如欧式或者余弦。


第四、电影的名称,名称上进行寻找关联性,听上去很扯,但其实有一定的逻辑在里头,比如我在视频网站搜索“三国”,显然我期望从名称上寻找三国相关题材的视频,他们就是在名称上建立起关联关系的,所以,名称从某种程度上来说,可以体现相关性。在计算相似或者相关方式上,我们可以进行分词,去除停词,然后再以词维度进行余弦计算。


第五、候选集电影的评分,对于做推荐来说,首先需要保证的推荐的候选集一定是优质的,从这个维度上说,抛开其他因素,那么就是整体评分高的电影是相对优质的电影。在处理的过程中,由于一个电影对应多个评分,所以,我们需要进行进行归一计算,最简单的做法就是计算整体评分的平均值,作为电影的评分数据,评分过低的数据直接从候选集中干掉,又大大的降低了计算次数。


三、代码逻辑


Spark2.0之后,不用再构建sparkcontext了,以创建一个复合多功能的SparkSession替代,可以正常的从HDFS读取文件,也可以从Hive中获取DataFrame等等。

val sparkSession = SparkSession   
.builder()
.appName("base-content-Recommand") //spark任务名称
.enableHiveSupport()
.getOrCreate()

那三个表可以先load到Hive中,然后spark直接从Hive中读取,形成DataFrame。

//从hive中,获取rating评分数据集,最终形成如下格式数据(movie,avg_rate)   
val movieAvgRate = sparkSession.sql("select movieid,round(avg(rate),1) as avg_rate  from tx.tx_ratings group by movieid").rdd.map{
f=>
(f.get(0),f.get(1))
}
//获取电影的基本属性数据,包括电影id,名称,以及genre类别   
val moviesData = sparkSession.sql("select movieid,title,genre from tx.tx_movies").rdd
//获取电影tags数据,这里取到所有的电影tag
val tagsData = sparkSession.sql("select movieid,tag from tx.tx_tags").rdd

先对tag进行处理,很多tag其实说的是同一个东西,我们需要进行一定程度上的合并,这样才能让tag更加的合理(有朋友有意见了,就一个实验案例而已,搞这么复杂),举个简单例子,blood、bloods、bloody其实都是想说这个电影很血腥暴力,但是不同的人使用的词不同的(这点大伙儿可以自由查看实验数据),所以我们需要进行一定程度上的合并。

val tagsStandardizeTmp = tagsStandardize.collect()   
val tagsSimi = tagsStandardize.map{
f=>
var retTag = f._2
if (f._2.toString.split(" ").size == 1) {
var simiTmp = ""
     val tagsTmpStand = tagsStandardizeTmp
.filter(_._2.toString.split(" ").size != 1 )
.filter(f._2.toString.size < _._2.toString.size)
.sortBy(_._2.toString.size)
var x = 0
   val loop = new Breaks
tagsTmpStand.map{
tagTmp=>
val flag = getEditSize(f._2.toString,tagTmp._2.toString)
if (flag == 1){
retTag = tagTmp._2
loop.break()
}
}
((f._1,retTag),1)
} else {
((f._1,f._2),1)
}
}

其中getEditSize是求取,两个词的编辑距离的,编辑距离在一定时候,进行合并,具体逻辑见代码了,不复杂。

def getEditSize(str1:String,str2:String): Int ={   
if (str2.size > str1.size){
0
 } else {
//计数器
   var count = 0
   val loop = new Breaks
//以较短的str2为中心,进行遍历,并逐个比较字符
   val lengthStr2 = str2.getBytes().length
var i = 0
   for ( i <- 1 to lengthStr2 ){
if (str2.getBytes()(i) == str1.getBytes()(i)) {
//逐个匹配字节,相等则计数器+1
       count += 1
     } else {
//一旦出现前缀不一致则中断循环,开始计算重叠度
       loop.break()
}
}
//计算重叠度,当前缀重叠度大于等于2/7时,进行字符串合并,从长的往短的合并
   if (count.asInstanceOf[Double]/str1.getBytes().size.asInstanceOf[Double] >= (1-0.286)){
1
   }else{
0
   }
}
}

继续对tag进行处理,统计tag频度,取TopN个作为电影对应的tag属性。

val movieTag = tagsSimi.reduceByKey(_+_).groupBy(k=>k._1._1).map{   
f=>
(f._1,f._2.map{
ff=>
(ff._1._2,ff._2)
}.toList.sortBy(_._2).reverse.take(10).toMap)
}

接下来处理年龄、年份和名称,这个会简单点,进行分词处理的话,怎么简单怎么来了,直接使用第三方的HanLP进行关键词抽取作为分词结果,直接屏蔽了停用词。

val moviesGenresTitleYear = moviesData.map{   
f=>
val movieid = f.get(0)
val title = f.get(1)
val genres = f.get(2).toString.split("|").toList.take(10)
val titleWorlds = HanLP.extractKeyword(title.toString, 10).toList
val year = movieYearRegex.movieYearReg(title.toString)
(movieid,(genres,titleWorlds,year))
}

取年份的正则函数如下,是个Java写的精通工具类(Scala和Java混写,简直无比美妙)。

package utils;   
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Desc: 抽取年份公式
*/
public class movieYearRegex {
private  static String moduleType = ".* \\(([1-9][0-9][0-9][0-9])\\).*";
   public static void main(String[] args){
System.out.println(movieYearReg("GoldenEye (1995)"));
   }
public static int movieYearReg(String str){
int retYear = 1994;
       Pattern patternType = Pattern.compile(moduleType);
       Matcher matcherType = patternType.matcher(str);
       while (matcherType.find()) {
retYear = Integer.parseInt(matcherType.group(1));
       }
return retYear;
   }
}

通过join进行数据合并,生成一个以电影id为核心的属性集合。

val movieContent = movieTag.join(movieAvgRate).join(moviesGenresTitleYear).map{   
f=>
//(movie,tagList,titleList,year,genreList,rate)
   (f._1,f._2._1._1,f._2._2._2,f._2._2._3,f._2._2._1,f._2._1._2)
}

相似计算开始之前,还记得我们之前说的吗,可以进行候选集阉割,我们先根据一些规则裁剪一下候选集。

val movieConetentTmp = movieContent.filter(f=>f._6.asInstanceOf[java.math.BigDecimal].doubleValue() < 3.5).collect()   

然后真正的开始计算相似,使用余弦相似度计算,取排序之后的Top20作为推荐列表。

val movieContentBase = movieContent.map{   
f=>
val currentMoiveId = f._1
val currentTagList = f._2 //[(tag,score)]
   val currentTitleWorldList = f._3
val currentYear = f._4
val currentGenreList = f._5
val currentRate = f._6.asInstanceOf[java.math.BigDecimal].doubleValue()
val recommandMovies = movieConetentTmp.map{
ff=>
val tagSimi = getCosTags(currentTagList,ff._2)
val titleSimi = getCosList(currentTitleWorldList,ff._3)
val genreSimi = getCosList(currentGenreList,ff._5)
val yearSimi = getYearSimi(currentYear,ff._4)
val rateSimi = getRateSimi(ff._6.asInstanceOf[java.math.BigDecimal].doubleValue())
val score = 0.4*genreSimi + 0.25*tagSimi + 0.1*yearSimi + 0.05*titleSimi + 0.2*rateSimi
(ff._1,score)
}.toList.sortBy(k=>k._2).reverse.take(20)
(currentMoiveId,recommandMovies)
}.flatMap(f=>f._2.map(k=>(f._1,k._1,k._2))).map(f=>Row(f._1,f._2,f._3))

最后,将结果存入Hive中,Hive中提前建好结果表。

//我们先进行DataFrame格式化申明   
val schemaString2 = "movieid movieid_recommand score"
val schemaContentBase = StructType(schemaString2.split(" ")
.map(fieldName=>StructField(fieldName,if (fieldName.equals("score")) DoubleType else  StringType,true)))
val movieContentBaseDataFrame = sparkSession.createDataFrame(movieContentBase,schemaContentBase)
//将结果存入hive,需要先进行临时表创建
val userTagTmpTableName = "mite_content_base_tmp"
val userTagTableName = "mite8.mite_content_base_reco"
movieContentBaseDataFrame.registerTempTable(userTagTmpTableName)
sparkSession.sql("insert into table " + userTagTableName + " select * from " + userTagTmpTableName)

到这里,基本大的代码逻辑就完了,可能还有一些边边角角的代码遗漏了,但不妨碍主干了。


05 融合用户兴趣的推荐才个性


接上个章节,我们给了一个最最最简单的推荐系统机制,即基于内容属性的相似或者相关推荐,我们知道这种推荐机制基本只基于内容本身的属性进行推荐,与用户没有半毛钱关系,所以,当然也就说不上个性化了。


0.5.1 个性化与用户画像


在说具体的情况之前,我们先来思考一个问题,什么是个性化?个性化一定是与人相关的,只有人才有个性,每个人可能都有自己的个性,推送的信息如果能满足用户的个性,才是一个好的推荐系统,才具有足够的智能。


而今天,我们要讨论的就是,如何让推荐从非智能的过程演变为知晓用户个性,基于用户偏好进行推荐,从而变得更“聪明”点,也就是智能化。


要实现推荐个性化,那么先需要对用户进行分析,分析用户的偏好,然后根据偏好来做推荐,就顺其自然了。而要分析用户的偏好,那么自然就少不了对用户行为的分析。


所以,核心还是用户画像的分析,然后我们再基于用户画像属性进行推荐,由于用户画像体现的是每个用户的偏好数据,所以,不管怎么样,这种推荐机制或多或少都是能体现一些个性化的东西的。

沿着这个路径,我们依然是结合实际数据以及代码案例来分解这个个性化推荐的过程。


0.5.2 基于用户画像的个性化推荐策略


整个案例代码的逻辑是,我们先根据行为数据,进行用户的画像描述抽取,然后再结合用户的画像数据为用户进行信息推荐,注意,这里与之前的实例不同的是,我们是基于用户进行推荐的,而上个实例是在浏览某个内容的时候,进行相关内容推荐,这里以及进化到了根据人进行推荐了。


实践数据源


关于数据源,依然使用的是上个案例中的实验数据,不清楚的见上一个章节(最简单的推荐系统)的原始数据说明,从上次的数据源说明情况看,实际上打标行为数据有10万条,评分数据有100万条,相对于电影内容数据实体来说,其实已经算不少了,所以,不用担心,针对于有行为记录的用户,或多或少还是能描述出他们各自的一些行为偏好的。


用户兴趣标签提取


基于上个小节的流程图,所以,在实践中,我们首先需要做的就是用户兴趣标签的提取。我们核心拥有的就是用户对电影的打标签数据,以及用户对电影的评分数据。


所以,从上面两个行为数据集中,我们可以尝试提取以下几个维度的用户偏好数据:

  • 用户对电影类目偏好数据,即用户对那些类目偏好。

  • 用户的偏好兴趣标签,即通过用户对电影的偏好标签打标行为,进一步可以提取用户的兴趣标签。

  • 用户的偏好年份,通过打分数据,描述用户偏好哪个年代的电影。


我们先解决用户的偏好标签问题,我们已有的是用户对电影的打标行为数据,实际上这是电影层级的标签,所以我们需要在这个基础上,最终直接为用户映射上这些特征标签。


所以,我们需要对单个用户的所有打标数据进行合并(标签会做预处理),然后如果用户对刚好打标的电影有评分的话,还需要带上评分权重,最终合并这些标签,形成用户带权重(本身的频度、对应电影的评分)的标签集,这就是用户的一些兴趣点。


对于类目偏好,说起来就简单了,比如通过评分表,我们把对应所有的电影都取出来,然后分析其类目,将评分作为对应类目的权重,然后将类目进行合并,最终求取用户的类目偏好合集。


对于电影年份,过程与上述取类目的过程类似,最终获取到年份偏好。


电影数据的处理


假设在上面的基础上,我们已经获取了用户层级的画像属性信息,比如偏好的电影类别,偏好的特征标签,偏好的某些年份的电影(同个时代电影具有一些相同的电影,比如10年前的电影风格与现在的俨然不同,年份在某种程度上说还是有影响的,虽然很弱)。


接下来,我们需要绘制候选集电影的属性(取之前,做一些初筛过滤操作,减少计算量),对应用户的属性,同样是三个,其中年份、类目都是直接存放于电影表中,唯一需要额外处理的就是特征Tag了,由于不同人对不同的电影进行Tag标记,上面进行用户画像绘制的时候,是以人为维度的,现在已电影为维度,进行标签合并,最终同样可以形成电影维度的标签集。


关联推荐计算


每个维度分别进行计算相似度或者相关度,然后不同维度进行合并归一计算最终的用户与电影的相关度。最外层我们依然以权重模型去做,以经验来看,类目是最重要的,其次是Tag,最后才是年份属性,至于最终怎么调整还是需要根据实际反馈数据来做微调,现在就拍脑袋吧。

我们来看代码逻辑


至于说取原始数据的过程,就不多说了,具体的可以看上面那个案例,这里就不贴代码片了,这里所有表的数据都会用到,所以都要获取。


第一步,先进行movie候选集的处理,包括Tag预处理,合并,以及类目年份的获取


我们进行相似tag合并操作,返回的数据形态是(mvieid,tag)集合,但tag会做提前进行预处理,过程依然跟上次一样,进行编辑距离相近的词合并。

val tagsStandardizeTmp = tagsStandardize.collect()   
val tagsSimi = tagsStandardize.map{
f=>
var retTag = f._2
if (f._2.toString.split(" ").size == 1) {
var simiTmp = ""

     val tagsTmpStand = tagsStandardizeTmp
.filter(_._2.toString.split(" ").size != 1 )
.filter(f._2.toString.size < _._2.toString.size)
.sortBy(_._2.toString.size)
var x = 0
    val loop = new Breaks
tagsTmpStand.map{
tagTmp=>
val flag = getEditSize(f._2.toString,tagTmp._2.toString)
if (flag == 1){
retTag = tagTmp._2
loop.break()
}
}
(f._1,retTag)
} else {
f
}
}

我们先将预处理之后的movie-tag数据进行统计频度,直接作为tag权重,形成(movie,tagList(tag,score))这种数据集形态。

val movieTagList = tagsSimi.map(f=>((f._1,f._2),1)).reduceByKey(_+_).groupBy(k=>k._1._1).map{   
f=>
(f._1,f._2.map{
ff=>
(ff._1._2,ff._2)
}.toList.sortBy(_._2).reverse.take(10).toMap)
}

接着进行genre类别以及抽取电影属性的年份属性,其中涉及的正则方法见上一个实例,这里就不重复给出了。

val moviesGenresYear = moviesData.rdd.map{   
f=>
val movieid = f.get(0)
val genres = f.get(2)
val year = movieYearRegex.movieYearReg(f.get(1).toString)
val rate = f.get(3).asInstanceOf[java.math.BigDecimal].doubleValue()
(movieid,(genres,year,rate))
}

最终将三种不同的属性进行合并,形成电影的处理过的候选集,当然还有电影的平均评分rate属性,这是判断电影基本水平的标志。

val movieContent = movieTagList.join(moviesGenresYear).filter(f=>f._2._2._3 < 2.5).sortBy(f=>f._2._2._3,false).map{   
f=>
//userid,taglist,genre,year,rate
   (f._1,f._2._1,f._2._2._1,f._2._2._2,f._2._2._3)
}.collect()


第二步,我们进行用户画像属性的获取


先通过rating评分表与tags表进行关联join,获取用户直接与tag的关联关系,这样评分数据就可以当成单个tag的权重进行计算了,并且通过DataFrame的API操作会更方便,所以可以先将之前处理的tagsSimi转换成DF,然后直接可以使用类似SQL的逻辑关系了。

val schemaString = "movieid tag"   
val schema = StructType(schemaString.split(" ").map(fieldName=>StructField(fieldName,StringType,true)))
val tagsSimiDataFrame = sparkSession.createDataFrame(tagsSimi.map(f=>Row(f._1,f._2.toString.trim)),schema)
//对rating(userid,movieid,rate),tags(movieid,tag)进行join,以movieid关联
//join步骤,将(userId, movieId, rate)与(movieId, tag)按照movieId字段进行连接
val tagRateDataFrame = ratingData.join(tagsSimiDataFrame,ratingData("movieid")===tagsSimiDataFrame("movieid"),"inner").select("userid","tag","rate")

接着进行类似reduce操作,在SQL中就是分组合并,将(userId, tag, rate)中(userId, tag)相同的分数rate相加。

val userPortraitTag = tagRateDataFrame.groupBy("userid","tag").sum("rate").rdd.map{   
f=>
(f.get(0),f.get(1),f.get(2).asInstanceOf[java.math.BigDecimal].doubleValue())
}.groupBy(f=>f._1).map{
f=>
val userid = f._1
val tagList = f._2.toList.sortBy(_._3)
.reverse.map(k=>(k._2,k._3)).take(20)
(userid,tagList.toMap)
}

在处理完用户的兴趣Tag之后,处理其他属性,Year属性。

val userPortraitYear = userYear.rdd.map(f=>(f.get(0),f.get(1),f.get(2))).groupBy(f=>f._1).map{   
f=>
val userid = f._1
val yearList = f._2.map(f=>(f._2,f._3.asInstanceOf[java.math.BigDecimal].doubleValue())).toList.take(10)
(userid,yearList)
}

进行用户的genre偏好处理。

val userPortraitGenre = userGenre.rdd.map(f=>(f.get(0),f.get(1),f.get(2))).groupBy(f=>f._1).map{   
f=>
val userid = f._1
val genreList = f._2.map(f=>(f._2,f._3.asInstanceOf[java.math.BigDecimal].doubleValue())).toList.take(10)
(userid,genreList)
}

对于每一个用户来说,在计算待推荐列表时,都需要移除自身已经看过的电影,先获取用户的观看列表。

val userMovieGet = ratingData.rdd.map(f=>(f.get(0),f.get(1))).groupByKey()


第三步,进行电影画像与用户画像的匹配计算


在实际的计算过程中,每个同纬度的属性进行相似计算,最终外层通过权重模型进行打分,然后重新排序,获取每个用户的对应的待推荐电影TopN,记得要移除自身已看过的电影列表。

val portraitBaseReData = userPortraitTag.join(userPortraitYear).join(userPortraitGenre).join(userMovieGet).map{   
f=>
val userid = f._1
val userTag = f._2._1._1._1
val userYear = f._2._1._1._2
val userGenre = f._2._1._2
//用于做差集计算,移除已经看过的电影
   val userMovieList = f._2._2.toList
val movieRe = movieContent.map{
ff=>
val movieid = ff._1
val movieTag = ff._2
val movieGenre = ff._3
val movieYear = ff._4
val movieRate = ff._5
val simiScore = getSimiScore(userTag ,movieTag,userGenre,movieGenre,userYear,movieYear,movieRate)
(movieid,simiScore)
}.diff(userMovieList).sortBy(k=>k._2).reverse.take(20)
(userid,movieRe)
}.flatMap(f=>f._2.map(ff=>(f._1,ff._1,ff._2)))

其中函数getSimiScore相关的计算逻辑如下。

def getSimiScore(userTag:Map[Any,Double],movieTag:Map[Any,Int],   
                userGenre:List[(Any,Double)],movieGenre:Any,
                userYear:List[(Any,Double)],movieYear:Any,
                movieRate:Double): Double ={
val tagSimi = getCosTags(userTag,movieTag)
val genreSimi = getGenreOrYear(userGenre,movieGenre)
val yearSimi = getGenreOrYear(userYear,movieYear)
val rateSimi = getRateSimi(movieRate)
val score = 0.4*genreSimi + 0.3*tagSimi + 0.1*yearSimi + 0.2*rateSimi
score
}

至于每个维度的计算过程,这里就不列了,大同小异,只要逻辑走的通,具体可见源代码。


第四步,对结果进行存储。


最后,将计算的结果保存下来,同样,需要先进行表结构定义。

val schemaPortraitStr = "userid movieid score"   
val schemaPortrait = StructType(schemaPortraitStr.split(" ").map(fieldName=>StructField(fieldName,if (fieldName.equals("score")) DoubleType else  StringType,true)))
val portraitBaseReDataFrame = sparkSession.createDataFrame(portraitBaseReData.map(f=>Row(f._1,f._2,f._3)),schemaPortrait)
//将结果存入hive
val portraitBaseReTmpTableName = "mite_portraitbasetmp"
val portraitBaseReTableName = "mite8.mite_portrait_base_re"
portraitBaseReDataFrame.registerTempTable(portraitBaseReTmpTableName)
sparkSession.sql("insert into table " + portraitBaseReTableName + " select * from " + portraitBaseReTmpTableName)

至此,所有代码主体逻辑已经清晰了,其实说白了就是一个计算用户画像的过程,然后画像与待推荐主体之间的关联性。


0.5.3 实操中的注意事项

如上,基于用户画像的推荐机制在实际操作中,其实还有很多需要考虑的地方,并没有想象中简单。


比如,用户的行为并没有我们想象中靠谱。


所谓没想象中靠谱是说,一方面用户的行为数据,有时候并不是其兴趣特点所表现,这点很显然,比如如果系统把一些信息故意放在很显眼的位置,那么对于一般用户来说,不点也得点了,所以就会造成这种用户数据其实是不那么靠谱的。


另一方面是如果用户产生了行为数据,但是行为数据并不足够多,那么这个时候其实这些行为数据是有置信度的考量的,行为数据不够产生的描述是有可能形成偏差的,再根据有偏差的数据去做推荐,那结果只能是更离谱了。


用户兴趣时效性问题。


在上面的实验逻辑中,我们知道我们并没有对用户的行为数据做更多的过滤,而实际的操作中,用户的兴趣是有一定时效性的。举个例子,我在一年前看电影的记录,还适合放到现在做我的画像分析吗?不一定的,因为我的兴趣可能已经随时间偏移了,过去我所喜欢的东西,现在我已经不喜欢了。


所以,在一般实际操作的过程中,一定需要分辨用户的兴趣数据的有效性,一般情况下,我们会进行长期兴趣和短期兴趣的区分,人在一定时间内其兴趣是固定的,并且在一些很短暂的时间段内,比如一两天、甚至是一天内,其关注点是有一定意义的,这个时候其短期兴趣就生效了。


所以,我们在实际操作的时候,长期兴趣、短期兴趣的具体的应用就需要结合实际的场景的区分了,已经我们需要注意原始数据是否适合做兴趣描述的来源数据,是否已经失效。


冷启动的问题。


所有涉及到行为数据的推荐算法,都绕不开冷启动的问题,即一个用户是个新手,没有任何行为记录留下,这意味着我们就无法分析其画像了,这个时候就称之为该用户的冷启动。


在上上个章节中,我们有提到过一些解决冷启动的机制,比如基于内容推荐(见上个章节),进行热点内容推荐(比如把最热门的一些电影推给该用户),还比如根据整体数据做关联推荐(这个后面再讲),方式很多,效果不一,需要根据具体情况来看了,再不行就想办法在用户注册的时候尽可能的收集用户的静态数据,再根据用户的静态画像数据来推荐,总比乱推的好。


匹配计算的问题。


在上面的例子中,我们其实并没有做过多匹配计算逻辑的讲解,只是简单描述同纬度的进行相似计算,然后上层做权重模型,其实就是一种很普通的匹配计算的过程。准不准,难在于外层权重的合理性,具体过程见第二篇文章,这里就不过多阐述。


其实这算是我们有意为之了,如果有些时候没法让不同主体(用户&内容)形成同一个维度矩阵的时候,这个时候其实就要有比较合理的映射机制了,能让内容与用户的属性做关联计算。


0.5.4 信息补充


写到这里,结合实际的数据,Spak工程代码,我们成功的从呆板的属性推荐过渡到基于用户画像的推荐,并为推荐附上了个性化的能力,但实际上基于用户画像的个性化推荐依然是有缺陷的,比如他不会做用户兴趣的升级,而实际上一些知识本身就是具有一定的阶梯性的。


举个例子就很容易理解了,比如,你对大数据的东西很感兴趣,于是系统根据你的兴趣偏好天天给你推Hadoop、大数据各种技术框架等信息,在某个时间段可能是合理,比如我对大数据领域已经熟知了呢?你还给我天天推送大数据相关的信息。


而我实际上是需要寻求大数据关联的信息,甚至是升级的信息,比如基于大数据的机器学习、数据挖掘相关的东西,这个机制是无法做到这一层的。所以,学完了这个,还没完事,下个章节,我们将学习另一个推荐机制,这种推荐机制可以为你推送一些基于你兴趣之外的东西。


06 经典的协同推荐


接上一个章节,我们大致Get到了一个点,那就是如果要达到推荐个性化的目的,核心还是用户的行为数据,只有用户各自的行为数据才能反馈其与其他人所不一样的特性,从而有针对性的进行推荐。按上个章节的原话,大致就是这样的:


实际上基于用户画像的个性化推荐依然是有缺陷的,比如他不会做用户兴趣的升级,而实际上一些知识本身就是具有一定的阶梯性的。

举个例子就很容易理解了,比如,你对大数据的东西很感兴趣,于是系统根据你的兴趣偏好天天给你推Hadoop、大数据各种技术框架等信息,在某个时间段可能是合理,比如我对大数据领域已经熟知了呢?你还给我天天推送大数据相关的信息。

而我实际上是需要寻求大数据关联的信息,甚至是升级的信息,比如基于大数据的机器学习、数据挖掘相关的东西,这个机制是无法做到这一层的。


说白了其实就是基于用户画像的推荐,他无法发现新知识,所谓新知识就是,与你之前的兴趣爱好相对比,推荐的候选集永远圈定在你的兴趣标签维度内,做不到认知的升级,而实际上认知是会进行升级的,特别是随着你捕获的知识信息越多的情况下,你就越会对更上层的其他知识感兴趣,不断的深入下去。


而基于协同过滤的推荐,或多或少能解决一点这类问题,最起码能够结合本身用户的行为,让你触达新的知识信息,并且这种递进是通过协同关系得到的,意味着是大部分人的共同选择,所以还是具有一定合理性的。


0.6.1 协同的原理拆解


对于基于协同过滤的推荐,可谓是推荐系统中的经典推荐算法了,记得好像就是亚马逊推广出来的,然后大放光彩。协同过滤又分为基于用户的协同(UserCF)、基于物品的协同(ItemCF),以及基于模型的协同(ModelCF)。


基于用户的协同过滤推荐(UserCF)。


基于用户的协同过滤,即我们希望通过用户之间的关系来达到推荐物品的目的,于是,给某用户推荐物品,即转换为寻找为这个用户寻找他的相似用户,然后相似用户喜欢的物品,那么也可能是这个用户喜欢的物品(当然会去重)。


来看一个表格:

用户/物品

物品A

物品B

物品C

物品D

用户A

Y

Y

用户B

-

Y

-

-

用户C

Y

-

Y

Y

//其中Y表示对应用户喜欢对应物品,-表示无交集,?表示需不需要推荐。


这是一个最简单的例子,其实目的很简单,我们需要给用户A推荐物品,而且可以看到,用户已经喜欢了物品A和物品C,其实剩下也就B和D了,要么是B,要么是D。那么根据UserCF算法,我们先计算用户A与用户BC之间的相似度,计算相似,我们前文说了,要么距离,要么余弦夹角。


假如我们选择计算夹角(四维):cosAB=0(90度的夹角),cosAC=0.8199(角度自己算吧)。所以相比来说,我们会发现用户A与用户C的相似度是稍微大一些的。于是,我们观察用户C都喜欢了哪些物品,然后与用户的去重,然后会发现该给用户A推荐物品D。


简单来讲,UserCF就是如上过程,但在实际的过程中,数据量肯定不止这么点,于是我们需要做的是为用户计算出相似用户列表,然后在相似用户中经过去重之后,计算一个推荐的物品列表(在计算推荐物品的时候,可以叠加用户的相似程度进一步叠加物品的权重)。


然后在喜欢物品的表达形式上,可以是如上的这种二值分类,即Yes Or No,也可以是带有评分的程度描述,比如对于某个物品打多少分的这种表现形式。这样的话,针对于后一种情况,我们就需要在求在计算相似度时,加入程度的权重考量。


基于物品的协同推荐(ItemCF)


不同于基于用户的协同,这里,我们计算的是物品之间的相似度,但是,请注意,我们计算物品相似度的时候,与直接基于物品相似度推荐不同是,我们所用的特征并不是物品的自身属性,而依然是用户行为。


用户/物品

物品A

物品B

物品C

用户A

Y

-

Y

用户B

Y

Y

Y

用户C

Y

//其中Y表示对应用户喜欢对应物品,-表示无交集,?表示需不需要推荐。


同样,这是一个简单实例。目的也明确,我们在知道用户AB喜欢某些物品情况,以及在用户C已经喜欢物品C的前提下,为用户C推荐一个物品。看表格很简单嘛。只有两个选项,要么物品B,要么物品C。那么到底是物品B还是物品C呢?


我们来计算物品A与其他两种物品的相似度,计算向量夹角。对于用户A,物品A与物品B,则对于AB向量为(1,0),(1,1),对于AC向量为(1,1),(1,1),分别计算夹角cosAB=0.7,cosAC=1。或者用类似关联规则的方法,计算两者之间的共现,例如AB共现1次,AC共现2次。通过类似这种方式,我们就知道物品A与物品C在某种程度上是更相似的。


我要说的就是类似共现类做计算的这种方式,在大规模数据的情况下是很有效的一种方式,基于统计的方法在数据量足够的时候,更能体现问题的本质。


基于模型的协同推荐(ModelCF)。


除了我们熟悉的基于用户以及基于物品的协同,还有一类,基于模型的协同过滤。基于模型的协同过滤推荐,基于样本的用户偏好信息,训练一个模型,然后根据实时的用户喜好信息进行预测推荐。常见的基于模型推荐又有三种:最近邻模型,典型如K最近邻;SVD模型,即矩阵分解;图模型,又称为社会网络图模型。


最近邻模型


最近邻模型,即使用用户的偏好信息,我们计算当前被推荐用户与其他用户的距离,然后根据近邻进行当前用户对于物品的评分预测。


典型如K最近邻模型,假如我们使用皮尔森相关系数,计算当前用户与其他所有用户的相似度sim,然后在K个近邻中,通过这些相似用户,预测当前用户对于每一个物品的评分,然后重新排序,最终推出M个评分最高的物品推荐出去。需要注意的是,基于近邻的协同推荐,较依赖当前被推荐用户的历史数据,这样计算出来的相关度才更准确。


SVD矩阵分解


我们把用户和物品的对应关系可以看做是一个矩阵X,然后矩阵X可以分解为X=A*B。而满足这种分解,并且每个用户对应于物品都有评分,必定存在与某组隐含的因子,使得用户对于物品的评分逼近真实值,而我们的目标就是通过分解矩阵得到这些隐性因子,并且通过这些因子来预测还未评分的物品。


有两种方式来学习隐性因子,一为交叉最小二乘法,即ALS;而为随机梯度下降法。首先对于ALS来说,首先随机化矩阵A,然后通过目标函数求得B,然后对B进行归一化处理,反过来求A,不断迭代,直到A*B满足一定的收敛条件即停止。


对于随机梯度下降法来说,首先我们的目标函数是凹函数或者是凸函数,我们通过调整因子矩阵使得我们的目标沿着凹函数的最小值,或者凸函数的最大值移动,最终到达移动阈值或者两个函数变化绝对值小于阈值时,停止因子矩阵的变化,得到的函数即为隐性因子。


使用分解矩阵的方式进行协同推荐,可解释性较差,但是使用RMSE(均方根误差)作为评判标准,较容易评判。

并且,我们使用这种方法时,需要尽可能的让用户覆盖物品,即用户对于物品的历史评分记录需要足够的多,模型才更准确。


社会网络图模型


所谓社会网络图模型,即我们认为每个人之间都是有联系的,任何两个用户都可以通过某种或者多个物品的购买行为而联系起来,即如果一端的节点是被推荐用户,而另一端是其他用户,他们之间通过若干个物品,最终能联系到一起。


而我们基于社会网络图模型,即研究用户对于物品的评分行为,获取用户与用户之间的图关系,最终依据图关系的距离,为用户推荐相关的物品。

目前这种协同推荐使用的较少。


0.6.2 基于Spark的协同过滤实践


老规矩,大致过完了理论,我们来走一遭代码实践,数据源的解释不就多说了,依然还是那份电影数据,不清楚的见上上上一章节的的数据说明,这次我们只用到涉及到评分的数据,共100万条,我们通过评分行为来做协同过滤。


截止Spark2.X系列,Spark的MlLib只实现了基于矩阵分解的协同(也就是经典的基于ALS协同过滤),没有实现更常规的基于物品或者基于用户的协同过滤,但从上面的原理我们知道,其实基于物品基于用户的协同核心就在于构建基础向量矩阵以及计算相似的两个方面,我这边也是实现了,但基于篇幅这里,就只介绍基于ALS的实践过程了,其他两个案例,需要的话请联系我。


由于MlLib实现了算法模型,所以从敲代码的维度上来说,代码量反而会远远低于基于用户、基于物品的协同,甚至会少于之前的基于物品相似或者基于用户画像的推荐了,顺带说一句,基于ALS的推荐代码,其实网上很容易找,算法MlLib中的经典算法了,很多人都实现了,不过万变不离其宗(变个毛线,API接口就那几个,参数也就那几个,能怎么变)。


先Hive数据表中,将rating评分数据取出来(当然,如果你的机子跑不动,就limit一下简单取些数,跑通模型就得啦)。

val ratingDataOrc = sparkSession.sql("select userid,movieid,rate,timestame  from mite8.mite_ratings limit 50000")

将取出的评分数据,以时间构建Key-value键值对,形成(Int,Ratings)格式的数据,其实这是一个中间处理过程,方便后续的数据输入。

val ratings = ratingDataOrc.rdd.map(f =>   
(java.lang.Long.parseLong(f.get(3).toString)%10,
 Rating(java.lang.Integer.parseInt(f.get(0).toString),
   java.lang.Integer.parseInt(f.get(1).toString),
   f.get(2).asInstanceOf[java.math.BigDecimal].doubleValue())))

这里,鉴于计算能力,我就不进行全局用户的候选集推荐计算了,只拿ID=1的用户当成实验,获取ID=1的用户候选推荐列表,先取该用户的行为数据。

val personalRatingsData = ratingDataOrc.where("userid = 1").rdd.map{   
f=>
Rating(java.lang.Integer.parseInt(f.get(0).toString),
     java.lang.Integer.parseInt(f.get(1).toString),
     f.get(2).asInstanceOf[java.math.BigDecimal].doubleValue())
}

基于上上面的K-V中间数据,我们以取余的方式,将数据分成6:2:2,三个比例,分别进行模型训练,数据校验,以及结果测试。

val training = ratings.filter(x => x._1 < 6).values   
.union(personalRatingsData).repartition(numPartions).persist()
val validation = ratings.filter(x => x._1 >=6 && x._1 < 8).values
.repartition(numPartions).persist()
val test = ratings.filter(x => x._1 > 8).values.persist()

ALS的推荐效果评估,一般我们是以均方根差来离线衡量推荐的准确度,所以,这里涉及到了ALS参数调优的问题,我们通过数据来最终确定参数,并确定最终的Model,分别取ranks、lambdas、numIters作为调优对象。

var count = 0   
//进行三层循环遍历,找最佳的Rmse值,对应的model
for (rank <- ranks; lambda <- lambdas; numIter <- numIters) {
val model = ALS.train(training, rank, numIter, lambda)
//计算均根方差值,传入的是model以及校验数据
 val validationRmse = computeRmse(model, validation, numValidation)
count += 1
 //选取最佳值,均方根误差越小越OK
 if (validationRmse < bestValidationRmse) {
bestModel = Some(model)
bestValidationRmse = validationRmse
bestLambda = lambda
bestRank = rank
bestNumIter = numIter
}
}

基于上面最终选择的参数,输出Model,我们基于这个模型,去做最后的推荐,注意需要去除ID=1的用户已经观看过的电影。

//推荐前十部最感兴趣的电影,注意需要剔除该用户(userid=1)已经评分的电影,即去重   
val myRatedMovieIds = personalRatingsData.map(f=>f.product).collect().toSet
val candidates = movies.keys.filter(!myRatedMovieIds.contains(_))
//为用户1推荐十部movies,我们只做用户ID=1的推荐
val candRDD: RDD[(Int, Int)] = candidates.map((1, _))
val recommendations:RDD[Rating] = bestModel.get.predict(candRDD)
val recommendations_ = recommendations.collect().sortBy(-_.rating).take(20)

存储推荐的结果,主要Row需要先进行格式化。

//结果存储用户1的推荐结果   
val alsBaseReDataFrame = sparkSession.sparkContext
.parallelize(recommendations_.map(f=> (f.user,f.product,f.rating)))
.map(f=>Row(f._1,f._2,f._3))
//DataFrame格式化申明
val schemaString = "userid movieid score"
val schemaAlsBase = StructType(schemaString.split(" ")
.map(fieldName=>StructField(fieldName,if (fieldName.equals("score")) DoubleType else  IntegerType,true)))
val movieAlsBaseDataFrame = sparkSession.createDataFrame(alsBaseReDataFrame,schemaAlsBase)
//将结果存入hive
val itemBaseReTmpTableName = "mite_alsbasetmp"
val itemBaseReTableName = "mite8.mite_als_base_re"
movieAlsBaseDataFrame.registerTempTable(itemBaseReTmpTableName)
sparkSession.sql("insert into table " + itemBaseReTableName + " select * from " + itemBaseReTmpTableName)

最后再补上求均方根差的函数。

def computeRmse(model:MatrixFactorizationModel,data:RDD[Rating],n:Long):Double = {   
//调用model的predict预测方法,把预测数据初始化model中,并且生成预测rating
 val predictions:RDD[Rating] = model.predict((data.map(x => (x.user, x.product))))
val dataTmp = data.map(x => ((x.user, x.product), x.rating))
//通过join操作,把相同user-product的value合并成一个(double,double)元组,前者为预测值,后者为实际值
 val predictionsAndRatings = predictions.map{
x => ((x.user, x.product), x.rating)
}.join(dataTmp).values
//均方根误差能够很好的反应出测量的精密度,对于偏离过大或者过小的测量值较为敏感
 //计算过程为观测值与真实值偏差的平方,除于观测次数n,然后再取平方根
 //reduce方法,执行的是值累加操作
 math.sqrt(predictionsAndRatings.map(x => (x._1 - x._2) * (x._1 - x._2)).reduce( _ + _ )/n)
}

至此,整个代码逻辑就结束了,其实我们不难发现,被框架封装的算法,其实使用起来更加的简单,如果抛开校验以及优化模型的过程,总共代码都没有几行。


最后再补充一个点。


这里大家可能对为什么协同能够发现新物品,而基于用户兴趣的画像推荐不能,原则上说基于画像会将思维局限于画像兴趣的偏好内,但兴趣本身就会升级的,这是通过历史的单个用户的行为所不能推测的。


而基于协同不一样,他一方面考虑的用户的历史行为,另一方面他参考了该用户的周围协同的行为,而对于大部分人来说,共有的行为轨迹其实很多时候能够一定程度上体现用户的自我认知,以及认知升级的过程,这意味着物品之间的关联性本身就通过共有的用户行为天然关联,而协同就是要挖掘这种潜在的关联性,这无关物品之间的属性差异。


所以,从这个维度上说,协同是容易产生惊喜推荐的一种机制。


07 从推荐策略算法到系统,到数据架构,再到产品思维设计


接推荐系统系列的上一个章节,开篇2个章节我们从概念,从应用场景出发,大概的把推荐系统基础知识给大伙儿普及了一遍,接下来的三个章节,分别由浅到深,从理论到代码案例讲解几种不同推荐系统的策略或者推荐算法,看着整个系列从理论到案例,该有的都有了,其实不然,之前就有说过,推荐策略或者算法与推荐系统是有本质的不同的,而这一篇就是要把前面的东西进行收拢,从整体上进行收官。


虽然不再从策略维度再进一步深入,即这里不会再从理论到代码案例再深入讲策略,但是实际上推荐的策略是远不止如此的,并且从应用以及系统的角度来说,并没有说固定的策略可言。


 0.7.1 推荐策略以及算法的百家齐放


承上,我们讲了最基础的基于内容属性本身的相似关系进行针对物品的推荐,再到基于用户的兴趣属性进行推荐,再过渡到基于协同关系进行推荐,其实这些都算是推荐的策略,说的更技术点就是推荐的算法。


而推荐策略的想象力其实无限的,并不局限于某种固定的策略,只要从业务的角度走的通,其实都是可以的,当然具体的选择以及搭配问题,后面我会讲到。


我们来看已经归属于大腾讯的“起点中文网”的推荐。

PS:截图是我随意点击的一本小说《飞剑问道》,不重要,可以不care。


从他的推荐理由“喜欢这本书的人还喜欢”来看,显然是通过用户之间的阅读关联性来做的这次推荐,说的更通俗易懂点就是购物篮分析:买这个商品的人还经常一起买其他商品。


是不是逻辑关系很像?当然实际上到底是不是这种推荐策略,就需要起点的算法工程师出来讲话了,我个人只是从业务层往下进行追溯从而得出的结论。你看,我说的对不对,策略一层是没有定式,购物篮分析的逻辑依然是可以用在看文学站的推荐逻辑上,没毛病。


我们再来看一个策略,依然是腾讯的,腾讯社交广告一直对外宣称的技术“Lookalike”,翻译成技术语言就是“人群扩散算法”。简单的逻辑是,先找种子用户,然后基于用户画像和关系链(这是腾讯强项)挖掘相似用户,然后再将受众进行扩大。


具体示意图如下:

你觉得这是推荐?看着更像是广告投放,但广告的投放谁说不是一次信息主体的推荐呢?本质上应该是没有这么大的差距的,只是一个从业务的角度去描述,一个是更偏技术的角度的说法。


随着阿法狗诸如此类的人工智能应用的推广(造势),以及近几年计算能力的大幅提升,使得依赖于大计算能力的神经网络的相关算法得以大放光彩,基于神经网络的一些推荐算法或者策略也是一个大的研究方向。


综上,不必举过多的推荐策略或者算法例子了,核心想说的就是,其实策略层本身就是百花齐放的状态,甚至你随意光顾一些平台网站,都能遇到不同的策略和算法,甚至是搭配组合,没有限定的策略和算法层,只有不同不适应的应用场景,以及从策略到推荐系统层,其实还是有很多东西的。


0.7.2 从推荐策略算法到推荐系统


接上面的话题,从策略算法层到系统层,差的有哪些东西:

1.首先是策略并不等于系统,这是明确的,推荐的整体逻辑也未必是一种逻辑在里头,也可能是多种的策略组合。

2.其次,如何选择策略,如何组合策略,如何去评判,如何追踪效果,这点尤其重要。

3.对于整个系统级的支撑,在工程化,以及数据架构上如何去实现,才能支持上层的算法逻辑层。

4.产品层的策略对整个推荐系统的影响有多大。


如上四个问题都是从推荐系统的角度出发进行分析的,从这里我们知道,光知道策略或者推荐算法,是不是离推荐系统的构建还差那么好几个量级,02这个小节,我们先从1/2两个小点进行分析。


策略!=系统,这点是明确的,并且选择哪些策略去做推荐,本身就有严格的选择机制以及评判机制在里头的。

这张图片很有意思,是别人在脉脉上调侃各大大厂的推荐系统的话,挺有意思,另一方面也是可以侧面验证各大长的一些侧重点(不过有点为鹅厂说好话的嫌疑),不管,我们随拿一些实例来看看。


首先是豆瓣(当前主页是魔戒1的主页):

从直观的的角度讲,同类推荐的因素一定的在,比如《指环王》其他,比如哈利波特,加勒比海盗,但诸如大鱼、角斗士、勇敢的心、与狼共舞这些的逻辑就不得而知了。


从用户的角度上看,个人使用豆瓣电影也不算少,但几乎没有账号(但如果说没有账号就体系就推不准,那这个公司可以死球去了,有很多可以做类似唯一用户的判别的方式,诸如浏览器、电脑硬件地址、cookie等等),但从我的个人感知来看,推荐的效果一般般。


再换一个,这是某宝的(当前是一个iphoneX的购买主页):

诚如调侃所言,我吃完两馒头,再问我要不要两馒头,我搜索iphoneX,他问我要不要iphone从6到6s到8s,挨个问,也够累的,反正我是不喜欢这种格调。


再回到大腾讯,这是之前文章就涉及到的,腾讯视频的推荐:

当前页面为《海上牧云记》的播放页面,个人是腾讯视频的中长期会员,再看看他给我推荐的是什么?大部分都是类似的奇幻古装剧,而老实讲,我对这种剧着实不喜欢,拍的tmd的假,而我只是好奇点击进去的,So...


再说到腾讯的朋友圈广告的投放推荐,前段时间一直给我这种孩子都快打酱油的人推婚纱摄影,这是几个意思?


再多的例子这里就不举了,很多看其推荐的列表大致能猜测一些其推荐的策略重点,其实或多或少还真是与调侃的有一些相似之处,那从表面看起来大部分的推荐系统都不像那么高大上,问题出在哪,是他们的策略就是这么Low?是他们的算法工程师太菜?


其实核心问题在于推荐系统的评价机制,在实际的场景中,一切以效果评价为导向,将策略,甚至是组合推荐的策略往评价得分高的方向进行调整,对于整个系统来说才是有意义的,并不是说算法高深就一定好。


那么,具体什么是合理的评价方式呢,大部分来说都是为了让用户的挺溜时间加长,最直接的表现就是点击转化,但并不是完全绝对的。以百度的调侃为例,你要的是馒头,人家给你推荐的是馒头制造机。


这跟其商业模式是有一定的关联的,百度之前的核心就是关键词竞价广告,那么,他必然要衡量几个方面的东西,第一是关键词与搜索词的相关性,离太远太扯淡的不行;第二相关广告的竞价。


于是,他就需要衡量准与商业价值之间的关系了,所以,并不是一味地追求准确,而是追求在其中最佳的平衡点,能给百度带来最佳的广告收益转化。


再说其他的之前我所体验的推荐系统,他们就一定不准吗?或许以我个人的角度讲,他们推荐的并不是很符合我的口味,但是如果他们是从整体转化进行评判呢?这种机制是他们所有目前方案中的最佳转化方案,那为什么不能用?少数的个体badcase并不会影响整体的策略,也不用管low还是不low,抓住核心问题。


当然,不可否认的是,如果能满足所有的人的意愿认为它很准,又能让整体系统的转化做到最大化,那当然最好了。


所以,从推荐策略算法到推荐系统,最核心的一个东西就是评估机制,构建起完善并且合理的评估机制,有利于整体推荐系统的优化和改进。说到评价,那不得不说的就是AB测试了,一个好的推荐系统,一定是会带AB测试的,能够很好的进行策略对比,进行流量分配,效果展示等等。


0.7.2 推荐系统数据架构


前几天记得分享过朋友的一篇文章,核心就是讲推荐系统架构的。对于整个推荐系统来说,系统的架构设计会严重影响到整个系统的效果与上层应用的体验。


在第05个章节中,记得大致提到过基于用户画像推荐的短期兴趣与长期兴趣,其实长期兴趣的挖掘还好,基本基于离线的计算结果依然还是可行的,但是对于很多推荐机制来说,就是短期兴趣,更切确的说是你当前行为的兴趣表现。


这意味着,我需要实时的对你的浏览行为进行兴趣分析,然后实时的反馈给你推荐列表,这种机制看似简单脑残,但往往很有效,因为他足够实时,而在段时间内,人的注意力一般只会放在很垂直的某个点上,所以往往就很有效。


但是,看似简单的机制,对于这种需要支持实时分析,实时反馈的机制来说,架构的设计就是一个挑战。此外,在整体的系统构建过程中,你需要考虑算法逻辑层可迭代性的问题,即通过反馈数据能够不断的自动调整你的算法策略,从而让效果更佳,这些都是需要数据架构进行支撑的。


此外,就是上面说的AB测试,效果反馈机制,都是需要集成至整个推荐系统中,再有承接上层应用,你需要考虑好计算的效率与结果输出的效率问题,所以缓存的设计与缓存更新的机制又是个问题。


从整个架构层来说,其实是相对繁杂的,与我们之前所说的策略算法层,这是另外一个维度上的东西,需要我们从整体系统级别去考量。


归纳来说,其实从推荐系统架构设计的角度来说,需要考虑以下几个因素或者说有以下几个重要组成部分:

  • 数据的输入层,承接特征处理层,作为算法策略层的输入。

  • 推荐策略以及算法实现层,这就是我们说的百家齐放的那层。

  • 基于推荐算法的结果候选集,进行策略组合、排序以及召回,最终系统层吐出去的是这部分的结果,而非算法策略层的直接结果。

  • 推荐系统的数据反馈回收机制,不管是隐性的还是显性反馈。

  • AB测试分流机制。

  • 基于反馈数据以及AB测试结果的算法层动态迭代部分,包括基础的推荐算法,以及排序召回等部分。

  • 部分系统需要考虑实时数据的反馈流通应用问题。


至于说具体的推荐系统架构,相信大家随便一搜都能搜到很多架构图,可能略有偏差,但是个人感觉只要不违背如上的一些基本原则,大体上结合自身的场景去调整,是没有大毛病的,所以,这里就不给具体的架构逻辑图了。


0.7.3 从系统到产品策略层


说完推荐策略,再到推荐系统,再到系统架构,这些看似都是与数据、与算法严密相关的东西,单纯的以产品思维角度出发,你觉得在设计或者做一个推荐系统时,有什么需要考虑的吗?这个层面是很多技术人员很容易忽略的一部分。


其实只要用点心,就算不太care算法策略,也是大有可为的,以上面贴过的一张图为例。

我们来看他的左上角标题“喜欢这本书的人还喜欢”,其实这就是一种推荐解释,同理,我们可看亚马逊的推荐解释“买过这个商品的人还购买了”。


这就是所谓的推荐结果的可解释性,人往往信任一些可以解释、容易理解的东西,这也就是为何很多推荐系统都愿意去给出这种类似的推荐解释,因为这种行为可以提升可信度,而可信度可以增加用户的点击转化,所以,可信度也是推荐系统设计中的一个重要参考因素。


从上面这么多推荐案例中,我们不难发现一个共同特征,那就是右上角的“换一批”按钮,我们来思考一下这个按钮存在的意义。


任何一次用户点击这个换一批按钮,这就意味着我们收集到了用户的反馈行为,至于说这个反馈行为到底是正向的还是负向的,就得看具体分析了。比如一个用户一个推荐项都没有点,不断的切换推荐列表,直至放弃,这显然你的推荐列表不如人意,但该用户又是一个迫切需要推荐场景的用户。如果某个用户,在不断点击推荐项的同时,又在不断的切换列表,这意味着这个用户很乐意使用推荐的场景,并且推荐的列表还是可以的。怕就怕那种不点击,也不切换的用户,我们无法获取到更多的主动反馈了。


说到主动反馈,另外一个纯产品层的设计思路就是推荐项的主动反馈了,这点也是亚马逊首创,每个推荐项用户都可以打分,或者直接评判说喜欢与不喜欢。通过这种方式,不断的收集用户的喜好,然后融入策略算法层,才能让你的推荐系统更加的合理,体验更好。


所以,单纯的从产品层,也是有很多东西可以去研究的,对于整体推荐系统而言,他就是一个应用,无非是更偏向于数据、算法等维度的一个产品而已,我们可以从算法层去着手,也可以试图从产品层去优化。


07 总结补充


到这里,整个推荐长文基本就结束了,从整个文章的的逻辑我们知道,如果你要架设一个推荐系统,那么首先对于推荐系统的一些基本概念需要熟悉,然后了解不同的推荐策略,然后结合场景分析最佳的一些推荐策略算法,然后基于架构的考虑(不同层级的分离),搭建整个推荐系统,然后从产品的思维角度去优化,最终产出符合你业务特征的推荐系统。看着容易,其实操作起来还是有一定困难的。


推荐系统在一般业务规模小的时候,其实鸟用不大的,只有在业务有了一定规模之后,那么就到了锱铢必较的阶段了,使用推荐哪怕增加了5个点的增长转化,也是极好的,更何况可能远远不止呢。


目前很多主流推荐系统都是基于用户的画像、兴趣爱好推荐的(这是一种相对靠谱,又容易在大规模用户场景中使用的策略),你越是被他推荐的东西牵着走,你后续就会越陷入其中,最终导致了你所获取的信息一直都是圈定在某个范围内的,这就是所谓的“信息茧房”。


其实要形成信息茧房一方面是由于推荐机制导致的,另一方面跟场景也是有很大关系的,比如如果用户被你所推荐的东西所推动,那么就容易陷入这种状态,如果用户获取信息的渠道有多种(比如导航、搜索等等),那么就不那么容易。


典型如今日头条,如果在前期你不小心点击了一些比较low的内容,然后它就越给你推类似的文章,结果你越看,它就越推,于是你所看到的东西都是一大坨类似离谱八卦了。从直观的角度看,今日头条重度依赖于用户的阅读行为,而头条又是一个重推荐场景的产品,所以会相对容易陷入“信息茧房”的这种情况。


从目前看,头条解决这个问题的途径是,给出热度频道,这个逻辑一定程度上降低用户的兴趣偏爱分析,这样用户能够接触到信息面就会更广,进而促使用户能够调整其兴趣,不断的更新其兴趣。


单纯从转化的角度看来,短期内可能对于系统侧来说是正向的,因为他才不会关注到底是不是“信息茧房”,他只关注转化有没有提升,但长期来说,对于用户就是一种损害。所以,我们在考虑设计推荐策略算法的时候,多多少少都会考虑推荐的新颖性。


但新颖性这东西就是一个双刃剑,新的东西意味着不确定,不确定意味着可能低的转化,所以好的推荐系统一定是在确保你兴趣的同时,又会考虑新颖,并且这是一种顺其自然的推荐信息主体的过渡,构建起你偏好信息与新信息之间的关联性,让你同样有欲望去点击那些新的东西,不过这就很难是了。

对话王兴:太多人关注边界,而不关注核心

$
0
0



你做得越多,你的敌人就越多。

对于这句话,美团点评可能深有体会。这家公司曾经是一家团购公司,后来它变成了一家卖电影票的公司,它还被认为是一家外卖公司、一家餐饮公司或是一家旅行公司,最近它又进入了打车市场、支付市场,它甚至开起了线下零售店。它进入的领域太多了,以至于你很难准确描述美团到底是一家什么公司。唯一可以确定的是,它不停扩张、四处出击,它的对手包括了中国最强大的互联网巨头、最明星的创业公司和一些老牌互联网上市公司,并且每隔一段时间,就有对手在集中质疑它。

这家公司看来并不怯于战争,事实上,在每个它进入的领域都做得不错。美团点评2016年全年交易额是2400亿人民币,比2015年同期增长了50%,他们预计2017年交易额将达到3600亿。在刚刚过去的5月,公司已经从亏损到整体盈利,目前账上有200亿人民币现金。

在中国互联网中,美团是一家特殊的公司。大量公司是从垂直领域开始成长,然后不断延展,所以他们难免由行业思维出发,更多去思考终局和边界。而美团点评是用商业流转中的一个环节来作为自己的内核——这个内核从商业上看,是交易;从客户看,是服务。它的业务是横向的,所以王兴的思考和多数CEO不太一样,他更多通用的、跨界的思考。比如他对业务和竞争的看法,他认为不要期望一家独大,也不要期望结束战争,所有人都要接受竞合才是新常态,同时,他认为太多思考边界和终局是错误的,“哪有什么真正的终局?”他说。

 

今年5月,美团点评CEO王兴接受了《财经》杂志专访。距离上次《财经》杂志专访他已经过去了一年半。仔细对比,你会发现他和一年半之前对很多问题的思考都发生了变化。

以下是访谈的部分摘选。

 

|敌人与朋友

「中国过去几十年在美苏两个超级霸主中间的关系,有点像今天美团在腾讯、阿里之间。」

 

《财经》:最近关于美团点评的一系列报道看了吗?


 王兴:有一些看了,肯定看不全。

 

《财经》:你觉得这些报道是中立的,还是有立场的在黑你?


 王兴:有一些相对中立,有一些是非常恶意,而且非常没有底线。

 

《财经》:如果一个竞争对手持续黑你,并且你知道是谁的话,你会怎么处理?


王兴:我会和对方沟通,但这常常不太解决问题。我想起05年前后看过一篇《时代周刊》或是《纽约时报》写亚马逊的文章,开篇说这个公司已经十几年了,依然像一个跌跌撞撞的飞机,最后是拉起来还是坠下去,没有人知道。但十年后,大家都知道亚马逊是多么的厉害和有远见。所以有些质疑是正常的,我反对的是那些彻头彻尾的谎言,而且近乎人身攻击的。

 

《财经》:有人开玩笑说,半壁互联网江山都是美团的敌人。


王兴:数量并不是问题。我们是一家以客户为中心的公司,我们从来不是为了跟别人(成为敌人)。在对手这件事上,就像开车一样,你得偶尔看一下后视镜,但你不能盯着后视镜开车。

 

《财经》:多数优秀公司都是以客户为中心,但他们往往在一条主跑道上,或者两条。


王兴:当然不是。亚马逊一度做手机,他们还做过搜索、Prime,他们还被认为是Netflix最强的竞争对手。他们也是一个很全面的竞争。

 

《财经》:在你眼里什么是敌人?什么是朋友?


王兴:我不太喜欢敌人这个说法,我更愿意说是——同行公司。朋友是能与我们合作的公司。

 

《财经》:互联网圈有谁是你的朋友吗?


王兴:腾讯。同时它也是我们一个很重要的股东。

 

《财经》:你碰到过最尊敬的对手是谁?


 王兴:你重视他的战斗力和你尊敬他、认为他有竞技精神,是两码事。所以毛泽东说,在战略上你要藐视一切对手,在战术上要重视一切对手。从战斗力来说,阿里非常强,但如果他们各方面做得更有底线一点,我会更尊敬他们。

 

《财经》:阿里和腾讯都是美团的股东,和腾讯相处会比跟阿里相处容易一些吗?


王兴:不能说简单或是容易。但腾讯不管是创始人的个性、整个团队的气质,还是业务战略,它是能更好和别人结盟的。

 

《财经》:在美团与点评的合并中,据说你和腾讯联手把阿里请出去了。


王兴:这是误解。事实上美团点评在2015年10月合并之后,我还专门去拜访了马云和逍遥子。我认为前面有滴滴快的这个成功的例子——原来两家A、T打得不共戴天,后面握手言和,都成为滴滴的股东。所以我跟阿里说美团非常希望可以同时得到腾讯和阿里的支持,但他们说:“你完全搞错了,我们认为滴滴合并快的对阿里来说是一个失败的例子,我们不会让这种错误再次发生。”

 

《财经》:当时你怎么回答的?


王兴:我说腾讯已经答应进一步投资美团点评。阿里说,我们可以投钱给你,你要10亿美元可以,20亿美元也可以,我们都可以投,但是你不能再要腾讯的钱。可是,腾讯也是我们很重要的股东,而且是一个比较友好的朋友,所以我不觉得应该如此。

 

《财经》:听说阿里现在依然没有全部卖掉在美团的股票。


 王兴:还剩一点。它去年之所以兜售我们的老股是为了干扰我们融资。如果你不看好这家公司,那干脆卖光好了,我们已经帮他们找好了买家。但他却不肯卖光,他一定要留一点,或许是为了将来能继续给我们制造点麻烦。

 

《财经》:与阿里巴巴糟糕的关系,会给美团带来什么影响?


王兴:会面临更大的竞争压力。比如外卖,阿里为了给我们制造麻烦,不惜代价扶持饿了么,他们一年花了十亿美元。但归根到底最后还是看谁能给消费者提供更好的服务,否则即使你烧十亿美元,市场份额依然在下降。

 

《财经》:这是否也意味你在外卖领域始终无法赢得垄断性优势?


王兴:这是多数人的一个误解,不应该试图追求一家独大,和阿里的竞争会长期存在。


我和很多人沟通过「4321」,很多细分领域会经历多进4,4进3,3进2的过程。多进4就像百团大战、百车大战、百播大战,新机会出现时,一堆人冲上去,一段时间混战后可能有4家初步胜出,通常是BAT加上创业公司里的胜者,例如今日头条今天所面对的局面。但这不是个稳定结构,所以还会有4进3,3进2,比如百度外卖先出局了。除非像微信那样全国网络效应超强的业务,否则在很多领域是不会出现一家独大的。总有消费者喜欢不一样的品牌,可口可乐或是百事可乐,耐克或是阿迪。企业更不希望供应商只有一家。我觉得有两家是很正常的。

 

《财经》:你的同事王慧文说美团想做俄罗斯,在别人无法生存的地方也能生存。


王兴:所有比方都是有局限的。我会把美团点评比作中国,阿里和腾讯都喜欢自比美国,我觉得腾讯更像美国一点,而过去几十年中国在美苏两个超级霸主中间的关系,有点像今天美团点评在腾讯、阿里之间。

 

|竞争与合作

「我们不能靠烧钱烧赢打车这个市场。」

 

《财经》:美团点评为什么要做打车?


王兴:一方面现有网约车不能完全满足用户的需求。另一方面这是location  based service(基于位置的服务),美团的业务特征很大是和位置相关的。要么是服务提供者的位置,要么是服务需求者的位置,基于这个逻辑Uber也既做了打车又做了外卖,Uber全球有超过20%的订单是外卖。目前我们只派了一个小团队在南京这一个城市尝试。不仅打车,我们同时还在试其他很多东西。

 

《财经》:你曾经说美团做打车的逻辑之一是基于用户需求,用户去餐厅需要出行,需要打车。可打车路上用户可能也需要看淘宝,你为什么不做淘宝呢?


王兴:你不觉得关联会更远吗?当然新零售我们也干,我们马上要在线下开店。我们对业务的选择,和客户需求相关,也和业务能力相关。网约车和外卖的能力很像——偏线下结合、各个城市布点、用互联网提升体验、降低成本。

 

《财经》:是否会大规模烧钱去做打车?


王兴:你得明白一个事情做和不做的目的是什么,而不是简单的说做和不做。当年烧钱是为了教育乘客、司机以及普及手机支付,现在这个事情都完成了。而且,我们不能靠烧钱烧赢,而是应该提供更好的B端、C端体验,和更好的产品结合,然后让消费者做选择。

 

《财经》:美团点评有多大可能在打车市场做到第一名?


王兴:这倒不是我们的目标。其实一个行业都应该有至少两家参与者既是竞争也是合作,这样对用户和商家都会更好。

 

《财经》:为什么不选择和滴滴合作?


王兴:我们在点评上原先是有合作的,但我们在南京试点后,滴滴主动断掉了合作。其实滴滴要开放的话,我们愿意继续合作。我觉得大家得接受一点——竞合是未来的常态,新常态。

 

《财经》:美团目前也在做支付,未来会和微信支付产生竞争吗?


王兴:我不认为我们会在C端直接和微信支付或支付宝竞争,那是一个已经结束的战斗。但美团点评天生是一个交易平台,在商户那一端,因为我们合作了三四百万的商户,所以我们更多会用支付去帮助商户。

 

《财经》:有用户使用大众点评时,付款方式第一栏默认是银行卡支付,第二栏才是微信支付,而支付宝被折叠了。


王兴:哪种支付工具在最前面,主要取决于用户上回使用的是哪个支付工具。我们并没有把支付宝完全下掉,但支付宝的费率高得不合理。

 

《财经》:有人评价你是一个不善于合作的人。


王兴:看什么层面的合作。我们自己不开餐馆,不开酒店,不开电影院,我们跟三四百万商户合作。并不是所有人都像我们这样深刻认同以客户为中心,关键是对客户而言什么是对的。

 

|专注与多元化

「在科技变革的前半段,风险非常大,所以要用小团队去探索。但到了后半段,红利变小,整合成为了释放红利的方式。这时候多业务公司会比单一业务公司更有优势。」

 

《财经》:美团点评开新业务的逻辑是什么?


王兴:我们的使命是「We help people eat better,Live better」,中文是:让大家吃得更好,活得更好。在这个使命之下,我们认为凡是最终要发生的,我们就会选取合适的角度进入。现阶段美团点评是一个扩张的状态。

 

《财经》:美团的业务边界在哪里?还是完全没有边界?


王兴:太多人关注边界,而不关注核心。你可以把边界理解成万有引力,每一个物体因为质量的存在,它会产生引力,会影响其它所有物质。差别就在于——离核心越远,影响力越小,或者是它本身的质量越小,变得影响力越小。

 

万物其实是没有简单边界的,所以我不认为要给自己设限。只要核心是清晰的——我们到底服务什么人?给他们提供什么服务?我们就会不断尝试各种业务。

 

《财经》:你认为多元化和专注是什么关系?


王兴:我花了很多时间在思考这个问题。在科技变革的前半段,因为风险非常大,所以需要用小团队去探索。但到了后半段,红利变小,整合成为了释放红利的方式。这时候多业务的公司会比单一业务公司更有优势。

 

《财经》:美团点评有外卖、酒旅、打车、餐饮、电影票等各种业务,为什么同时做这么多业务,而不是把一个业务打深、打透?


王兴:举个例子,2003、2004年淘宝最重要的决定是做了一个什么都卖的大平台,而不是专注做一个女装品类或家电品类。如果美团只专注做电影票的话,是不可能赢的。

 

《财经》:你们有能力同时支撑这么多业务吗?


王兴:这道边界你不试是不知道的。如何判断一家公司是否有能力支撑更多业务?唯一的检验标准是看各个业务做得好不好。目前我们每个业务的经营状况都很好,同时我们有足够的现金储备——200亿现金。

 

外卖领域我们是第一,约占56%的市场份额,同时我们的效率比对手高很多。到店餐饮和猫眼电影都是行业第一。酒旅业务,我们的间夜数已经超过携程,估计再用1-2年,我们会超过整个携程加艺龙再加去哪儿的间夜数。还有一块是我们目前重点发展的餐饮生态平台,但还很早期,讨论第一、第二意义不大。

 

《财经》:但你在试验这道边界的时候不断增加了自己的敌人。


王兴:古人说“自返而缩,虽千万人,吾往矣!”首先我们要扪心自问做的事情是不是对的,如果是对的、该做的,哪怕对手如林,还是要义无反顾。

 

《财经》:200亿现金准备怎么花?我们还在继续融资吗?


王兴:餐饮是重中之重。我们并没有开启新一轮融资,但有一些股东在收我们的老股。

 

《财经》:外卖什么时候可以不再亏损?


王兴:亏损还会持续比较长的时间,因为还需要大量的投入,还有很多改造工作需要做。

 

《财经》:美团目前的几块业务,各自多长时间可以结束战役?


王兴:当我们的市场渗透率超过50%的时候,如果不犯愚蠢的错误,就很难被翻盘。我们希望每个领域都做到第一,至少确保第二。但我们并不指望完全消灭敌人,所有人在下半场都要接受竞合才是新常态。

 

《财经》:业界质疑,美团各个业务既看不到胜负终局,又看不到规模盈利的可能性。


王兴:我们上个月刚刚实现整体盈亏平衡。如果不开拓新业务,我们可以在一年之后规模盈利,但我不认为短期赢利是我们追求的目标。其实无论是讨论边界还是讨论终局都是一种思考角度,但并不是唯一的思考角度,哪里有什么真正的终局呢?终局本来是下棋的术语,可是,现在的实际情况是棋盘还在不断扩大。

 

《财经》:多业务的扩张方式是否会带来不安全感?


王兴:不断成长才能获取安全感。

 

《财经》:从战略维度上,美团先做什么,后做什么,做什么,不做什么。


王兴:一是进一步扩大我们所服务人群规模,中国有7亿网民,我们现在有2.4亿活跃买家,阿里有4.5亿活跃买家。所以我们还有两到三倍的增长空间。另一方面我们要「上天、入地」,长远看如果美团只做很浅的连接,那是没价值的。

 

所以我们在各个垂直行业都在做更深层次的连接。在餐饮,我们最早提供信息,后来提供交易,再提供外卖的配送。我们现在还给餐饮老板提供ERP系统,我们会往B端走,扎得更深。我认为这不光是美团一家该做的事情,所有试图有长期价值的公司都应该做,纯粹的C端、纯粹的连接,腾讯一个人干就好了。

 

《财经》:在生活服务领域里是否可能诞生BAT体量的公司?


王兴:光餐饮这个事就跟淘宝一样大了。我们今天来看搜索是一个巨赚钱的事情,但在它没赚钱之前,大家认为这是一个傻逼生意,雅虎显然是这么认为的。大家太容易设限,总看到这是目前最大的、一样大或者是小一个量级。大家没想到这其实是一个向更大量级过渡的中间阶段而已。

 

《财经》:所以你认为美团会成为BAT级别的公司。


王兴: B和A、T已经不是一个量级的。美团有机会成为A、T一个量级的公司因为我们创造的价值足够多,餐饮、旅游、到店综合品类每个领域都可以值几百亿美元。但需要的时间不短,至少五到十年吧。

 

《财经》:美团在商业上的核心价值是什么?


王兴:核心价值就是我们公司的使命「We  help people eat  better,live  better」,我们让大家吃得更好,活得更好。大家总是习惯用工具、入口、平台等概念来衡量公司的价值,这其实是语言对人的禁锢。一个公司的价值归根到底取决于你服务多少人,你给这些人创造了多大的价值。其它都是虚的。

 

正确定义、理解一个新东西是非常困难的。你创造了它,但要让人们接受一个原来不存在的概念,是很难的。过去所有的事都是美国先做,大家只要说我是中国的XX就完了,BAT是如此,滴滴也是如此。但美国没有一个单一对标美团的公司,美国也没有一个单一对标头条的公司。

 

《财经》:把多种商业模式拼凑在一起,这叫创造吗?


王兴:我们也改变它的使用方式,我们改变了大家吃饭的方式、途径,几百万餐馆的生意也会有很大的变化。其实世界上没有什么事情本质上是新的,只是方式上是新的。

 

《财经》:最终想把美团做成一家怎样的公司?


 王兴:一家长期有耐心、不断成长的公司。一位德国思想家曾经说过,作家可以分三类——流星、行星、恒星。书是如此,在这个时代更加如此,自媒体、公众号、公司,多数像是流星,非常绚烂,但一颗流星烧完就烧完了;行星可以长久存在,但它不会自己发光;恒星会发光,同时它和流星的发光方式不一样,流星是燃烧掉了,恒星是靠核聚变,所以恒星必须够大。

 

我们在努力成为恒星。美团到现在只有7年,大众点评也只有14年,我们只是刚刚起步而已。

 

《财经》:你认为对用户来说,美团有不可替代性吗?


王兴:一方面我们认为在具体层面上没有,不会有其它公司完全干我们的事情可以干得这么好。另一方面,这世界上没有任何东西是不可替代的,除了这个世界本身。

 

《财经》:感觉美团的业务正在往上走一个台阶,但危机四伏。


 王兴:我对危机四伏的理解是——我们遇到一个问题,但其实这个问题就是遇到下一个问题的过程。生于忧患,死于安乐,我们还远没有到可以安乐的时候。

 

|进攻与等待

「你做得足够好,使自己立于不败之地,但这不代表你能胜,只有当你的对手做了愚蠢的事情,你才能胜。」

 

《财经》:你怎么理解「战斗」?


 王兴:我看过一本美国退役的特种兵指挥官写的书,书名叫《mission,men and  me》mission是使命,men就是团队,最后才是自己。我理解的战斗就是mission 、men、me。

 

《财经》:有人评论美团在千团大战、以及最早进入酒旅时,都是别人在打仗在烧钱的时候美团在等待,美团是靠等待成功的。


王兴:一位参加过对越自卫反击战的投资人跟我说,多数人对战争的理解是错的,战争不是由拼搏和牺牲组成的,而是由忍耐和煎熬组成的。《孙子兵法》说过“不可胜在己,可胜在敌”,确实团购的事情不是我们打赢的,不是我们打倒了对手,是他们自己绊倒的。

 

《财经》:除了等待,在几场关键战役上,美团还做了什么?


王兴:我们有积极的耐心。比如酒旅,在我们入场之前,携程只有小几万家酒店,还有几十万家还没去签,我们去了。用户从PC向手机迁移时,我们提供了更好的用户使用方式。同时我们一开始就IT化了,每一个订单的服务成本是比携程低很多的。所以,你理解以客户为中心就是理解业务的本质和关键。

 

《孙子兵法》还有一句话“胜可知,而不可为”,你做得足够好,使自己立于不败之地,但这不代表你能胜,只有当你的对手做了愚蠢的事情,你才能胜。比如,你觉得去哪儿是怎么输掉的?是因为他们不够有耐心。

 

《财经》:在竞争中,最害怕的是什么?


王兴:害怕自己懈怠。

 

《财经》:美团有一支地推铁军,一支能在街头和饿了么打架的队伍,而你本来看上去攻击力很弱,你真的喜欢并认可这种铁军文化吗?


王兴:我们教育员工要非常节制。我们不是一个打架的公司,我们不是为了把某些人干掉,战斗对于我来说是一种手段和方式,是阶段性的。

 

很多人说我攻击性很弱,不光我的攻击性不高,我们的高管看起来攻击性也很弱,但这并不是关键。比如美国历史上著名的军事家马歇尔,他从来没有上过战场,但他做了很多正确的决定,比如在二战爆发迅速扩充美国军队,该换人的时候换人,甚至把下级提成上级。他本人的战斗力和攻击性很强吗?可能未必,但这不妨碍他成为人类历史上最大战争中最大赢家的最高指挥官。

 

|民主与决策

「如果有人不认可,他可以不加入这个公司,我们不需要讨好所有人。」


《财经》:美团是如何做决策的?外卖、打车这种新业务,想了多久决定去做的?


王兴:打个比方,一位摄影师在比赛中得了金奖,有人问他得奖照片拍摄花了多长时间?也许按下快门只需要0.001秒,但是他为了找到这个机会花了10年。我们做决策也是一样。

 

《财经》:你的同事说,光「eat  better,live  better」这句话你就整整想了一年。


王兴:我总是花很长时间同时思考很多问题,我喜欢在问题当中跳来跳去。而且「使命」这个问题是如此之难,世界上只有少数公司正确制定了他们的使命。

 

《财经》:当时想了哪些维度?


王兴:我们干的事情、我相信的事情。我相信永恒的事情,我希望使命像北极星一样永远清晰,指引你不停努力,所以我们既要确立一个足够宏大的终极目标,即「Live  better」。但同时你的使命又要足够明确而具体,和我们最靠近的事情就是「Eat  better」。

 

《财经》:你的高层说你做决策极慢。


王兴:跟我的思考方式有关系,也跟我尽量调整自己的职责有关系。我应该做少数重大的决策,而不是快速做大量的决策。

 

《财经》:决策慢,有没有真正遗憾和错过的事情。


王兴:很多创业者认为他错过了很多创业机会,但其实那不是他的机会。

 

《财经》:你的员工说,当他们问你一个事情怎么解决,他们想要答案,但你总是给他们方法。


王兴:当我认为一个事情很重要,而且能帮助他们成长,我会倾向于给他们思考的方法而不是答案。因为我的速度再快、决策质量再高,能做的事情也是有限的。

 

《财经》:但你给员工思维三段论,他们就真的会思考了吗?


王兴:有些人会有,有些人不会。

 

《财经》:如果中层跨级来找你,你会怎么处理?


王兴:我会了解情况,但我不会直接去做决策。

 

《财经》:你的管理层抱怨说你有时候太过民主了。


王兴:公司决策不存在民主的问题,而是参与度的问题。我认为美团的管理风格不能称为「民主」,而是大家广泛参与。当然,在使命、价值观这些问题上我不认为要靠民主来决策。

 

《财经》:民主会让很多员工感到很茫然吗?


王兴:当然会,别说民主了,很多人甚至恐惧自由,因为自由意味着责任。Liberty  means  responsibility,that  is why  most  people dread it。

 

《财经》:你有一个被广为人知的名言——多数人为了逃避思考,愿意做任何事情。你既然知道这一点,为什么还要民主呢?


王兴:我们愿意反复筛选,反复培养愿意思考的少数人。如果有人不认可,他可以不加入这个公司,我们不需要讨好所有人。

 

|管理与信任

「公司文化就像希腊神话的西西弗斯,你要推石头上去,它会掉下来,你再推上去,它会再掉下来。这是一个很苦难的过程。」

 

《财经》:你现在直接管多少人?


王兴:11个。

 

《财经》:公司员工有多少人?


王兴:3.1万,我们刚合并的时候3.5、3.6万。我们花了一年的时间,缩到3.1万。

 

《财经》:员工规模这么大,如何管理?


王兴:3.1万其实在中国不算一个大公司。其实你管3千人,3万人、30万人,对CEO来讲你直接管的人是不会有太大的变化的。

 

《财经》:美团最近的招聘风波,一个项目leader说不招聘东北、黄泛区人士,这是否是管理上出了问题?


王兴:那个招聘需求太夸张了,那个人不是HR,他可以有他个人的观点,但是他个人的观点不代表公司的立场。所有公司的管理都时刻存在问题,就像人体一样,体内总是有各种细菌、病毒、癌细胞,关键在于你是不是能及时解决这些问题。

 

《财经》:辞退是最好的解决办法吗?如果外界不知道,是否还会辞退?


王兴:看整个事情带来什么样的影响,其实这对员工有很大的影响。他讲得很荒谬,例如说不招东北人,可是你看王慧文就是东北人。

 

《财经》:美团很多高管都是你的同学,有人评价这是因为你不容易相信人。


王兴:创业初期高管是同学不是再自然不过的事情吗? 谷歌是两个同学创业,雅虎是两个同学创业,微软也是。我一离开学校就创业,不认识任何人,只认识同学。当然现在高管团队早就不只是同学了,有原来美团的高管,有原来点评的高管,也有从腾讯、百度和其他公司过来的优秀同行。

 

《财经》:如何帮助高管成长?


王兴: TOP这个词,可以把它分解成三个词——talent、opportunity、patience。这个人需要有天分、有才能,有合适的机会,同时还有长期的耐心才能成长起来。当然我认为自己确实是很幸运的。

 

另一方面,因为美团的业务足够复杂、足够完整、新业务足够多,管理层有机会像CEO一样,真正接近商业的本质,思考很核心的问题。

 

《财经》:你的中高层都是清楚理解并认可公司战略的吗?如果有不明白的,怎么解决这个问题?


王兴:想要每个员工都理解公司的使命和战略方向,需要将战略层层分解、向下传达。我们在努力往这个方向做,这也是唯一可行的方式。

 

《财经》:过去一年,你认为自己作为管理者最大的进步是什么?


王兴:我更加有意识地思考长期问题。

 

《财经》:目前在管理上遇到最大的挑战是什么?


王兴:公司文化的问题。公司文化是创始人的投射和延伸,越初期越是如此。清华希望它的学生毕业之后有「健全人格、宽厚基础、创新思维、全球视野和社会责任感」,我非常认同,我是这个公司的创始人,或快或慢,或早或晚,这个公司会像我这样。但如果做得不好,就会有断层、有变形。

 

《财经》:现在哪方面出现断层和变形了?


王兴:总体和内外部的沟通做得不够。公司文化就像希腊神话的西西弗斯,你要推石头上去,它会掉下来,你再推上去,它会再掉下来。这是一个很苦难的过程,但就是如此。文化也是一个没有终局的事情,我觉得太多考虑终局是错误的。

 

|思考与表达

「最糟糕的事情是一个公司设定一个目标,但它其实是达不到的,因为那个战略定位一开始就是错的。」

 

《财经》:最近在读什么书?


 王兴:关于一战的书我还没有看完,从一战爆发一百周年我就开始看那本书,现在都还断断续续没有看完。

 

《财经》:一位认识你很久的朋友说觉得你越来越好斗。


 王兴:还好吧。

 

《财经》:你打过架吗?


王兴:在小学一二年级打过,那时候男孩是通过打架来确定领导地位。我小时候非常瘦弱,但战斗力很强。成年之后就再没有打过架了。

 

《财经》:你小时候的理想实现了吗?


王兴:我小时候没有一个明确单一的理想。最近几年我有一个想法,我暂且把它称为地球代表计划。假设某一天我们要开一个银河系的会议,我要作为地球的唯一代表去参加这个会议。我要跟外星人怎么介绍地球呢?那时候我应该见过这个星球上最壮丽的自然景色、最繁华的都市,领略过最棒的美食、文学和音乐,尽可能的接触过人类文明的精华。当然,商业也是地球上一个很重要的力量。

 

《财经》:做过最长期的事情,除了创业还有什么?


王兴:活着是一个人所做的最长期的事情。活着,然后思考,然后创业。我很喜欢钱穆「过去未去,未来已来」这个说法。我觉得最长远的事情,一个是你做的事情,从什么时候开始做,到现在有多长的时间。另一个是你想的事情能够影响多远。所以我们努力把美团点评打造成一个基业常青的公司。

 

《财经》:听说你最近造了一个词?


王兴:谬望。因为我发现最糟糕的事情是一个公司设定一个目标,但它其实是达不到的,因为那个战略定位一开始就是错的。这就是谬望。大家经常讨论希望、讨论失望、讨论绝望,但如果人们真的能看清楚环境,就不太可能发生绝望的事情。

 

我最近觉得我不单对我的公司有责任,对我所处的中国有责任,我对中文都有责任。我经常发现一个英文词没有一个合适的中文翻译,一开始我抱怨居然没有人翻译,后来我觉得可能我应该去翻译它。

 

《财经》:对公司、对中国、对世界、对中文都有责任,好庞大的责任感。


王兴:责任感历来是以自我为中心的。我从来思考问题都不思考问题本身,而是思考我们所处的环境。因为你看不懂你所处的环境,就看不懂自己。

 

比如很多人会混淆科学、技术与科技,我曾经想过我应该写一篇文章讲「技术跟科技的区别」,帮大家理清概念。

 

《财经》:如何获得进步?


王兴:要么是看书,要么是跟人交流,不管是公司内部,还是公司外部的人,我和非常多的人交流。

 

《财经》:很多人认为你是一个不爱表达的人,但为什么你在饭否上那么有表达欲?


王兴:饭否的表达形式决定它是负担最小的,我有一句话想说就说了。

 

《财经》:现在花时间最多的是?


王兴:一是思考顶层业务之间的关系,二是人才组织的成长。

 

《财经》:现在最关心什么问题,最不关心什么问题?


王兴:最关心团队成长的问题,因为一方面我们面临大量机会,我们也有很好的战略位置,另一方面我们有足够的钱,我们的现金流已经转正。现在最大的瓶颈就是人,而人的成长是不能速成的。至于我不关心的问题,当然我也不知道它的存在。   

 

《财经》:每天花在思考工作上的时间和花在思考其他事情上的时间比例是多少?


王兴:我不觉得这两个很可分。你的思维是停不下来的。

 

《财经》:你认为TMD中谁最有可能成为BAT级别的公司?


王兴:都有机会,都不容易,都不会短期发生。但首先,B和AT不是一个量级。第二,AT还会比现在大很多,他们会繁荣很长时间。

 

《财经》:你觉得目前中国互联网的竞争环境,尤其是舆论环境,能不能允许美团点评这样的公司存在?


王兴:我们会把它做成的,我们不需要别人允许我们怎么样。

 

 

点击阅读原文,可以对照阅读《财经》杂志在2016年1月对王兴的采访「专访王兴:多数人为了逃避思考愿意做任何事情」

如何定位那些SQL产生了大量的redo日志

$
0
0

在ORACLE数据库的管理、维护过程中,偶尔会遇到归档日志暴增的情况,也就是说一些SQL语句产生了大量的redo log,那么如何跟踪、定位哪些SQL语句生成了大量的redo log日志呢? 下面这篇文章结合实际案例和官方文档“How to identify the causes of High Redo Generation (文档 ID 2265722.1)”来实验验证一下。

首先,我们需要定位、判断那个时间段的日志突然暴增了,注意,有些时间段生成了大量的redo log是正常业务行为,有可能每天这个时间段都有大量归档日志生成,例如,有大量作业在这个时间段集中运行。  而要分析突然、异常的大量redo log生成情况,就必须有数据分析对比,找到redo log大量产生的时间段,缩小分析的范围是第一步。合理的缩小范围能够方便快速准确定位问题SQL。下面SQL语句分别统计了redo log的切换次数的相关数据指标。这个可以间接判断那个时间段产生了大量归档日志。

/******统计每天redo log的切换次数汇总,以及与平均次数的对比*****/
WITH T AS 
(
    SELECT TO_CHAR(FIRST_TIME, 'YYYY-MM-DD')    AS LOG_GEN_DAY, 
           TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME, 'YYYY-MM-DD'), 
                       TO_CHAR(FIRST_TIME, 'YYYY-MM-DD'), 1, 0))
                , '999') AS "LOG_SWITCH_NUM" 
    FROM   V$LOG_HISTORY 
  WHERE FIRST_TIME < TRUNC(SYSDATE)  --排除当前这一天
    GROUP  BY TO_CHAR(FIRST_TIME, 'YYYY-MM-DD') 
)
SELECT  T.LOG_GEN_DAY
          , T.LOG_SWITCH_NUM
          , M.AVG_LOG_SWITCH_NUM
      , (T.LOG_SWITCH_NUM-M.AVG_LOG_SWITCH_NUM) AS DIFF_SWITCH_NUM
FROM  T CROSS JOIN 
(
    SELECT  TO_CHAR(AVG(T.LOG_SWITCH_NUM),'999') AS AVG_LOG_SWITCH_NUM
    FROM T
) M
ORDER BY T.LOG_GEN_DAY DESC;
SELECT    TO_CHAR(FIRST_TIME,'YYYY-MM-DD') DAY,
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'00',1,0)),'999') "00",
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'01',1,0)),'999') "01",
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'02',1,0)),'999') "02",
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'03',1,0)),'999') "03",
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'04',1,0)),'999') "04",
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'05',1,0)),'999') "05",
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'06',1,0)),'999') "06",
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'07',1,0)),'999') "07",
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'08',1,0)),'999') "08",
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'09',1,0)),'999') "09",
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'10',1,0)),'999') "10",
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'11',1,0)),'999') "11",
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'12',1,0)),'999') "12",
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'13',1,0)),'999') "13",
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'14',1,0)),'999') "14",
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'15',1,0)),'999') "15",
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'16',1,0)),'999') "16",
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'17',1,0)),'999') "17",
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'18',1,0)),'999') "18",
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'19',1,0)),'999') "19",
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'20',1,0)),'999') "20",
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'21',1,0)),'999') "21",
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'22',1,0)),'999') "22",
                TO_CHAR(SUM(DECODE(TO_CHAR(FIRST_TIME,'HH24'),'23',1,0)),'999') "23"
FROM V$LOG_HISTORY
GROUP BY TO_CHAR(FIRST_TIME,'YYYY-MM-DD') 
ORDER BY 1 DESC;

如下案例所示,2018-03-26日有一个归档日志暴增的情况,我们可以横向、纵向对比分析,然后判定在17点到18点这段时间出现异常,这个时间段与往常对比,生成了大量的redo log。


clip_image001 

clip_image002

这里分享一个非常不错的分析redo log 历史信息的SQL

-----------
REM Author: Riyaj Shamsudeen @OraInternals, LLC
REM         www.orainternals.com
REM
REM Functionality: This script is to print redo size rates in a RAC claster
REM **************
REM
REM Source  : AWR tables
REM
REM Exectution type: Execute from sqlplus or any other tool.
REM
REM Parameters: No parameters. Uses Last snapshot and the one prior snap
REM No implied or explicit warranty
REM
REM Please send me an email to rshamsud@orainternals.com, if you enhance this script :-)
REM  This is a open Source code and it is free to use and modify.
REM Version 1.20
REM
------------------------------------------------------------------------------------------------
set colsep '|'
set lines 220
alter session set nls_date_format='YYYY-MM-DD HH24:MI';
set pagesize 10000
with redo_data as (
SELECT instance_number,
       to_date(to_char(redo_date,'DD-MON-YY-HH24:MI'), 'DD-MON-YY-HH24:MI') redo_dt,
       trunc(redo_size/(1024 * 1024),2) redo_size_mb
 FROM  (
  SELECT dbid, instance_number, redo_date, redo_size , startup_time  FROM  (
    SELECT  sysst.dbid,sysst.instance_number, begin_interval_time redo_date, startup_time,
  VALUE -
    lag (VALUE) OVER
    ( PARTITION BY  sysst.dbid, sysst.instance_number, startup_time
      ORDER BY begin_interval_time ,sysst.instance_number
     ) redo_size
  FROM sys.wrh$_sysstat sysst , DBA_HIST_SNAPSHOT snaps
WHERE sysst.stat_id =
       ( SELECT stat_id FROM sys.wrh$_stat_name WHERE  stat_name='redo size' )
  AND snaps.snap_id = sysst.snap_id
  AND snaps.dbid =sysst.dbid
  AND sysst.instance_number  = snaps.instance_number
  AND snaps.begin_interval_time> sysdate-30
   ORDER BY snaps.snap_id )
  )
)
select  instance_number,  redo_dt, redo_size_mb,
    sum (redo_size_mb) over (partition by  trunc(redo_dt)) total_daily,
    trunc(sum (redo_size_mb) over (partition by  trunc(redo_dt))/24,2) hourly_rate
   from redo_Data
order by redo_dt, instance_number
/

image

分析到这个阶段,我们还只获取了那个时间段归档日志异常(归档日志暴增),那么要如何定位到相关的SQL语句呢?我们可以用下面SQL来定位:在这个时间段,哪些对象有大量数据块变化情况。如下所示,这两个对象(当然,对象有可能是表或索引,这个案例中,这两个对象其实是同一个表和其主键索引)有大量的数据块修改情况。基本上我们可以判断是涉及这个对象的DML语句生成了大量的redo log, 当然有可能有些场景会比较复杂,不是那么容易定位。

SELECT TO_CHAR(BEGIN_INTERVAL_TIME, 'YYYY-MM-DD HH24') SNAP_TIME, 
       DHSO.OBJECT_NAME, 
       SUM(DB_BLOCK_CHANGES_DELTA)                     BLOCK_CHANGED 
FROM   DBA_HIST_SEG_STAT DHSS, 
       DBA_HIST_SEG_STAT_OBJ DHSO, 
       DBA_HIST_SNAPSHOT DHS 
WHERE  DHS.SNAP_ID = DHSS.SNAP_ID 
       AND DHS.INSTANCE_NUMBER = DHSS.INSTANCE_NUMBER 
       AND DHSS.OBJ# = DHSO.OBJ# 
       AND DHSS.DATAOBJ# = DHSO.DATAOBJ# 
       AND BEGIN_INTERVAL_TIME BETWEEN TO_DATE('2018-03-26 17:00', 'YYYY-MM-DD HH24:MI') 
                                       AND 
           TO_DATE('2018-03-26 18:00', 'YYYY-MM-DD HH24:MI') 
GROUP  BY TO_CHAR(BEGIN_INTERVAL_TIME, 'YYYY-MM-DD HH24'), 
          DHSO.OBJECT_NAME 
HAVING SUM(DB_BLOCK_CHANGES_DELTA) > 0 
ORDER  BY SUM(DB_BLOCK_CHANGES_DELTA) DESC;

clip_image003

此时,我们可以生成这个时间段的AWR报告,那些产生大量redo log的SQL一般是来自TOP Gets、TOP Execution中某个DML SQL语句或一些DML SQL语句,结合上面SQL定位到的对象和下面相关SQL语句,基本上就可以判断就是下面这两个SQL产生了大量的redo log。(第一个SQL是调用包,包里面有对这个表做大量的DELETE、INSERT操作)

clip_image004

如果你此时还不能完全断定,也可以使用下面SQL来辅佐判断那些SQL生成了大量的redo log。 在这个案例中, 上面AWR报告中发现的SQL语句和下面SQL捕获的SQL基本一致。那么可以进一步佐证。 

注意,该SQL语句执行较慢,执行时需要修改相关条件:时间和具体段对象。

SELECT TO_CHAR(BEGIN_INTERVAL_TIME,'YYYY_MM_DD HH24') WHEN,
             DBMS_LOB.SUBSTR(SQL_TEXT,4000,1) SQL,
             DHSS.INSTANCE_NUMBER INST_ID,
             DHSS.SQL_ID,
             EXECUTIONS_DELTA EXEC_DELTA,
             ROWS_PROCESSED_DELTA ROWS_PROC_DELTA
FROM DBA_HIST_SQLSTAT DHSS,
         DBA_HIST_SNAPSHOT DHS,
         DBA_HIST_SQLTEXT DHST
WHERE UPPER(DHST.SQL_TEXT) LIKE '%<segment_name>%'  --此处用具体的段对象替换
  AND LTRIM(UPPER(DHST.SQL_TEXT)) NOT LIKE 'SELECT%'
  AND DHSS.SNAP_ID=DHS.SNAP_ID
  AND DHSS.INSTANCE_NUMBER=DHS.INSTANCE_NUMBER
  AND DHSS.SQL_ID=DHST.SQL_ID
  AND BEGIN_INTERVAL_TIME BETWEEN TO_DATE('2018-03-26 17:00','YYYY-MM-DD HH24:MI')
  AND TO_DATE('2018-03-26 18:00','YYYY-MM-DD HH24:MI')

其实上面分析已经基本完全定位到SQL语句,剩下的就是和开发人员或Support人员沟通、了解是正常业务逻辑变更还是异常行为。如果需要进一步挖掘深入,我们可以使用日志挖掘工具Log Miner深入分析。在此不做展开分析。 其实个人在判断分析时生成了正常时段和出现问题时段的AWR对比报告(WORKLOAD REPOSITORY COMPARE PERIOD REPORT),如下所示,其中一些信息也可以供分析、对比参考。可以为复杂场景做对比分析(因为复杂场景,仅仅通过最上面的AWR报告可能无法准确定位SQL)

clip_image005

clip_image006

此次截图,没有截取相关SQL,其实就是最上面分析的SQL语句,如果复杂场景下,非常有用。


clip_image007 

clip_image008

参考资料:

  • How to identify the causes of High Redo Generation (文档 ID 2265722.1)

相关文章


腾讯养蛊:赢了市场,苦了项目

$
0
0

3月15日,《绝地求生:刺激战场》登陆海外市场。游戏的英文版叫《PUBG Mobile》,翻译过来就是“绝地求生手游版”,小标题“刺激战场”被拿掉了。

也就是说,光子吃鸡成了绝地求生手游面向国际市场唯一的正版门面。

腾讯鼓励内部竞争,这是从端游时代就延续下来的优良传统。2013年的UP+发布会上,腾讯提出了“鸡蛋要放在很多篮子里”里的说法,当时他们最成功的产品还是《穿越火线》,同时腾讯又代理、自研了一共十几款FPS,这些产品现在大多数已经难寻踪迹,早已停服,但曾几何时,都是腾讯游戏大军中的一份子。

后来腾讯代理的LoL火了,腾讯故技重施,又把当时市面上比较有潜力的MOBA游戏也代理了过来,所以腾讯有了《超神英雄》(HON)和《神之浩劫》(Smite),后两者的国服早已凉凉。

《超神英雄》的国服官网永远停在了上次内测上,仅存这一个页面

外界把这种自家同时开发几个同类竞品的行为,叫做养蛊。

整个腾讯集团,最著名的养蛊案例发生在互联网从桌面向移动转型的时期。当时腾讯要做一个移动通信应用,内部三个团队同时开拔,最后张小龙的QQ邮箱团队成为蛊王,做出微信,为腾讯拿到了这把移动互联网的金钥匙。

之后,这种内部竞争策略屡试不爽,在很多重要关头立了大功。去年被人民网九评的现象级游戏《王者荣耀》,也是内部竞争的产物。只不过,当年光子的《全民超神》败给了天美的《王者荣耀》,如今风水轮转,天美的《全军出击》不敌光子的《刺激战场》。

从上架加拿大先行测试,到登顶全球105个国家的App Store游戏下载榜,《刺激战场》用时一个星期,成了腾讯新蛊王。

这场吃鸡手游大战前前后后打了小半年,市场预算多到不知往哪花,倒是让一众渠道媒体过了个好年。决战圈缩倒最后,基本上已经有了结论,网易的《荒野行动》或许还有一战之力,但在大盘上,腾讯已经稳操胜券。

飞龙骑脸你怎么输?


1

对,在吃鸡这个赛道上,腾讯又赢了。好马都在自己手里,想输也挺难的。但对赛道上的马儿来说,就不是那么回事了。

你们谁还记得《光荣使命》?

上线前,这个游戏算是万众期待,在TapTap创下了200万预约的纪录。后来传出腾讯代理的消息,众人也道是姿势虽不雅,但好歹抱上了金大腿,这波不亏。

但后面的发展急转直下,上线慢了不说,游戏硬伤也一大堆,内部要和亲儿子《CF荒岛特训》竞争,外部又被网易《荒野行动》狙击,后面腾讯的两款正版手游一出,相当于直接宣告凉凉。

最惨的是,上线才几个月,《光荣使命》连自家的官方微信和微博都已经没人管了。这两个账号的运营主体都是腾讯,微博2月23号之后便处于停摆状态,评论里挤满了吐槽游戏问题的玩家,无人应答,公众号已一整月未更新。现在这个游戏还活着的唯一痕迹,只有官网的更新公告。


凉不凉是一回事,用不用心运营,是另一回事。


一个产品是否成功,自身的努力和历史的进程固然都要看。但所谓尽人事听天命,就是说不管天命怎样,人事要做全了。不单是为了对得起自己,也是为了对得起依旧留在这个游戏里的玩家。

但在腾讯,最常见的情况,就是像这样, 产品还没凉,项目组自己先弃疗了。


2


牺牲品不只是《光荣使命》。

今年二月底,《堡垒之夜:大逃杀》在Twitch直播平台上的观众人数,超越了《绝地求生》,成为了Twitch上最受关注的大逃杀类游戏。不是小超是大超,根据Superdata的数据,上个月底《堡垒之夜》观众总数已经达到1400万,而《绝地求生》只有870万。

这个游戏的国服,同样在腾讯的手里。

但和《绝地求生》的大规模宣传不同,《堡垒之夜》的国服始终藏着掖着,虽然1月推出的中文版玩家已经发现可以用QQ直接登录,但到现在也没正式公布过代理消息。直到上周腾讯年报发布,才在里面提到两句。

一些和腾讯《堡垒之夜》项目打过交道的朋友告诉我,在腾讯内部,《堡垒之夜》已经定性要为《绝地求生》国服让路。原本早些时候打算PR一轮,取消了。在对外的宣传口径上,也绝不允许出现《堡垒之夜》压过《绝地求生》一头的情况。虽然在海外,前者早已超过后者一个身位。

《堡垒之夜》在国外有多火?这几天刚上了手游版,在美国App Store的排名依然在PUBG手游版之上,火到那边的学校开始针对性地屏蔽掉这个游戏的网络服务。

《堡垒之夜》火遍国外高校

这样的一个现象级产品,你给网易,给完美,给盛大,给了就是战略级产品,捧在手里怕化了,定要悉心运营。事实上,网易是如此眼红,真的自己抄了一个类似的游戏出来。

结果到了腾讯这边,说是养蛊也好,说是内部斗争也罢,直接给捂了下去。这还导致了一个问题,因为《堡垒之夜》是唯一一个和《绝地求生》有鲜明差异化又流行起来的吃鸡产品,它让吃鸡品类摆脱了千人一面的观感。但在中国,因为《堡垒之夜》的非正常状态,主流玩家接触到的,也只有《绝地求生》的克隆版们。

这样的市场挺无聊的。


3


腾讯运营游戏,有个不成文的思路:

任你国外再怎么成功,玩家有多期待,你在我这里数据不行,你就是个屁。

这种事情也不是第一次发生了。

很多人都知道全球收入第一的《怪物弹珠》,国服死在了腾讯手里,但未必知道是怎么死的,常人说起,只道是日本手游水土不服的又一案例。

但只要你玩过足够久的腾讯版《怪物弹珠》国服,就会深刻领教到当腾讯运营的产品数据表现不行时,那如坠冰窟的待遇。

早期腾讯对《怪物弹珠》抱的期望是不低的,毕竟是日本的国民游戏。但几次测试下来,留存数据并不理想,最终评级被调低,相应的也没有多少推广资源。

但这并不是《怪物弹珠》夭折的关键,这个游戏的国服虽说和日服不能比,但属于有一批自己的核心玩家,每到大的活动和版本更新基本上还能冲上畅销40的水平。这样的游戏,按理说稳定运营是没有问题的。

——如果说,运营态度 不那么消极的话。

但这只是如果。现实是,泛滥的运营事故和频出的低级BUG在整个游戏短暂的生命里贯穿始终,内容的更替完全无法满足玩家的正常游戏需求,项目组的不上心彻底让玩家感到灰心。最终,运营不到八个月便宣布停服。

“再见,腾讯曾经最好的手游,没有之一”

一年后,可能是有着《怪物弹珠》的前车之鉴,《智龙迷城》为了讨好本土玩家经过了一番腾讯式的大改,结果比《怪物弹珠》的陨落更加迅速,前后不到半年。

腾讯的停服,和大多数游戏的停服完全是两回事。一般来说,游戏到了末期,玩家数量剧减,收入难以支撑运营成本,开发商才会在无路可走的情况下选择停服。


但腾讯式停服,往往是在你觉得这个游戏其实还有救,用点心还能继续运营下去的时候,腾讯自己先放弃了。

形成鲜明对比的是去年下半年,Mixi自己在国内重开了《怪物弹珠》国服。至今半年多下载数才堪堪突破60万,在国内这个下载量算是很不起眼的数字,甚至游戏核心的联机体验尚且不如腾讯服,排名更在百名之外。可以说,状况比当年的腾讯服还要差上许多。

然而,健康有序的运营节奏和官方还算诚恳的态度,让新国服在核心玩家们的支持下依旧运营得有声有色,排名虽然低,但也稳定,还没有要凉的迹象。

我几年前玩了一个游戏叫《消灭都市》,一个小团队代理,当时国服刚出,也没什么推广,非常冷门。两年过去了,本来以为早已关服,结果一看公众号,依然在不断发布新的活动和内容更新的推送,点开一看,每篇推送只有几十个阅读,非常凄惨,但就是这样,这个游戏的国服依然在运营着,我去贴吧里瞅了一眼,玩家虽少,却都十分投入。

在腾讯版停服后自己重开的游戏,《怪物弹珠》也不是独一家。前两年韩国还有个很火的游戏,叫《龙界启示录》,也有着差不多的经历。当时腾讯去韩国签了一批游戏,有《七骑士》《天天富翁》,《龙界启示录》算是其中成绩比较差的,腾讯版停服后,开发商Gamevil把它改名为《星之后裔》,在国内重新上线,至今还在运营。

当时我去问开发商的人,为什么不和腾讯玩了。对方这样回答我:

“他们的产品太多,不重视我们的产品。他们的好产品太多了,他们并不在乎这一两款是什么样子。”

这就是现实,可能很多放别的公司手里要当宝贝供起来的产品,在腾讯,确实不算什么,多你一个不算多,少你一个不算少。

数据不好,评级下调,没有资源,都不是致命的。致命的是,这里的资源不仅包括市场资源,人也是一种资源,腾讯最好的人才永远留在最头部的项目里。谁会愿意在一个没有前途的项目组里呆着?要么人心离散,心里想着赶快嗝屁了好做下一个;要么跳槽跑路,去更有前途的项目组。对于他们来说,无非是停了一个三星小项目,这不是终结,而是新生。

但对玩家来说,三星项目也好,六星项目也罢,又有什么区别?我在你三星小项目里投入感情和金钱,那我活该被坑咯?



4


有人把腾讯的内部竞争文化比作是鲨鱼的子宫,因为鲨鱼会在胚胎时期就会吞食自己的兄弟姐妹,以确保自己能活下来。

这种文化给腾讯带来了强大的竞争力,也造成了一种局面:腾讯内部充满利益的牵扯和各种角力, 在数据驱动的核心逻辑下,腾讯对项目是没有感情的。

几年手游玩下来,我眼中称得上精品的游戏不多。《魔灵召唤》《阴阳师》《克鲁赛德战记》《魔龙之魂》《怪物弹珠》等等,算是其中的佼佼者。他们有的是现象级,有的是长卖的精品,成绩稳定,有口皆碑。他们有一个共同特点,都是慢热高门槛的手游,自带很强的用户筛选,不会一上来导一批量进去就会怎样怎样。

在腾讯,这样的产品是绝无可能活下去。

哪怕是《球球大作战》这样号称亿级用户的游戏,也不是一开始就爆了,而是靠慢慢运营做起来的,这种情况在腾讯这边,绝不会发生,所以腾讯拿了正版的《 http://Agar.io》,一样烂在了手里,却被巨人的李鬼《球球大作战》挟走了几亿用户。


因为对项目没有感情,没有爱,注定有一些领域腾讯是做不起来的,有些产品拿在手里也只是糟蹋。

腾讯自己未必没有意识到这个问题。当初网易的《阴阳师》大热,领导层就有过反思,觉得这样的产品,在腾讯的体系下是出不了头的。所以第二年UP发布会,腾讯就宣布了极光计划,要去做细分领域,扶持创意产品。

然而一年下来,极光计划摇摆不定,内部定位极其尴尬,很快极光的老大也要离职了,据说未来极光将会完全转向单机手游。

其实从最初宣传时候拿出来的那一波产品,就能预见到今天的局面。


整个系统的惯性问题,不是新开一条业务线就能解决的。


5

养蛊也好,内部竞争也好,数据驱动也好,他们的本质一样:都是企图用一种科学的管理方式和庞大的资源投入,去应对未来的不确定性。

这是很好的商业逻辑,却不是创作逻辑。

腾讯有《王者荣耀》,现在又有了《刺激战场》,都是很厉害的产品,后者甚至可能帮助腾讯打开全球市场的格局,可以说非常成功。

但回过头来看,在创作的层面上,腾讯庞大的自研体系里,这几年没有任何东西拿得出手,以至于,原来的《怪物猎人OL》项目组转型组建的Next部门,用远超独立游戏的成本做了一个“独立游戏”《死神来了》,被内部奉为榜样——因为特别缺乏这种创作的精神,所以整个集团都格外渴望这种精神。

确实,腾讯养蛊成功了。他们赢了市场,但又不知不觉输了些什么。

前几天,我在 《为什么洋人都在夸腾讯,你们还在骂腾讯?》的文章里,谈到了腾讯的口碑问题。当时的结论是,项目组基层不断出现的抄袭行为,使得腾讯大方向上做出的正面努力,不断被具体业务执行上的“土味”所掩盖。所以这几年来,腾讯虽然一直想要洗白,但过程非常缓慢。

这话其实只说对了一半。

腾讯的洗白之所以进展缓慢,很大一部分原因,也要归功于自家的冷血运营。

因为这种冷血运营,所有的产品只是冷冰冰的棋子。你会发现,现实中很难接触到腾讯的所谓“忠实用户”。虽然大家都在用腾讯产品,但是用户的认同度极差。

换句话说, 腾讯缺乏自来水。

缺乏“自来水”导致的后果就是, 关于腾讯的正面消息,很难得到自发的主动传播。而关于腾讯的负面消息,则很难被动消化,必须公关出力才有可能解决。这让他们想扭转口碑,要付出比正常情况下更多的代价。

前两天,互联网前辈Keso发了一篇文章,在业内广为流传,叫 《我为什么尊敬腾讯》。文章中提到,腾讯很早就把“成为最受尊敬的互联网企业”写在了公司愿景里,并举了若干的例子,来说明为什么自己喜欢尊敬腾讯。

作为知名的互联网大佬,Keso先生位高权重,我能充分理解为什么他这么喜欢腾讯——Keso先生接触的,是腾讯最有愿景的高层群体,平时可以在朋友圈与马化腾、张小龙谈笑风生。这些好友,格外富有人格魅力与才能,可以说互联网一等一的人才,怎么能不喜欢?

同理,在公司的战略层面,腾讯的确也让人讨厌不起来。这家公司近些年不遗余力打造口碑,年年都有高大上的概念和品牌推出,站在战略高位,一切看上去非常美好。

然而现实中,腾讯的口碑,却只是在极其缓慢地回暖,甚至稍微有一点负面,就直接让前面做的事情前功尽弃。因为基层用户接触到的,永远都是那个冷冰冰的腾讯,那个视所有产品为数据的腾讯。

产品对于腾讯只是养蛊素材吗?是的。

所以腾讯在人们心目中,依然是那个腾讯。


*知乎初来咋到,这是我发的第一篇文章,公众号上还有几篇(名字叫“对对对你们都是业内”),会不定期更新,要关注哪边的帐号就看你们随意了。

中国房价高的根本原因是什么? - 知乎

$
0
0

【2017年11月16日】为了防止有些人连最早的评论时间都不看一眼,这里补充一句话:这个回答是2013年写的。

以下原回答:


@杨小彻@冷哲的答案基本只说了土地成本这一个问题就共计得了1400多票,我实在忍不住要补充一下。两税制引发地方ZF收入下降,对卖地有了极高的热情,诚然不假,但各位有没有想过另一个问题—— 为什么土地越来越贵也依然能卖得掉?


我对中国的房价现象(我用的是现象,不是“高”,高不高且听分解)的看法是:这是中国社会和经济发展的必然结果。




1、严重的货币超发+资金流动渠道匮乏


货币超发的原因就不在这里展开了,单用数据说说货币超发严重到什么样。2012年底,中国广义货币M2余额为接近100万亿元,比1990年增长了65倍,甩出GDP涨幅八条街,同期的美国M2折合人民币也不超过60万亿元人民币。如果用M2/GDP来衡量货币超发情况,美国只有0.6到0.7,中国则高达1.87。(感谢数据帝 @chenqin指正错误)


这么多热钱流向哪里?中国经济发展到现在都面临一个尴尬的情况: 没有好的投资渠道。尤其是近十年汇率从8一路干到6,以及2008年来的经济波动,让很多出口企业、实业都遭到重创,创业环境不理想,创业信心不足,通货膨胀又让现金不断贬值,使得 房地产成为吸纳热钱的最大渠道。


事实上, 不断高攀的房价在近十年都扮演着中国经济的消化池,消化着大量的货币超发和肿胀的发展泡沫,否则今天的通货膨胀率、CPI增幅肯定远远超出我们的想象力和承受力,社会稳定一定会出现大问题。面对老百姓来讲,无非是一个直观的选择题——房子一年涨一倍和超市所有商品一年涨六倍你选择哪个?



2、贫富差距扩大+财富向能源和资源型阶层集中


首先贫富差距扩大是货币超发的一个副产品,因为超发的热钱基本被少数人圈走,普通的打工者、工薪阶层收入增幅是有限的。但这不是全部,和上一条一样,财富进入这些人手中,仍然面临的是流向问题。上一条说了选项的局限性,这一条要说的是选择者本身的局限性。


由于特殊的市场结构和经济现状,正常的努力创业致富所占的比例无法和完全的市场经济国家相比。我们都知道,在中国最容易致富的基本是两类:能源和资源。能源指的是挖煤挖矿的,资源指的是靠背景、渠道的。他们的共同点是: 挣快钱,且生意需要的循环投入少,会迅速积累现金,同时对自身素质文化要求不高,观念比较局限。


所以这些人有了钱能干什么呢?就是你所能看到的了:全世界买奢侈品、艺术品、豪车,赌场一夜千金,各种包养,但和买房子比起来,这些还是小钱。大宗的资金,最终主要还是流入了房地产。事实上,如果你关注艺术品市场的话,你会发现其涨幅远远甩开房价,归根到底都是一样的原因,只不过体量小又不关系国计民生,所以我们注意不到罢了。



3、人口红利+经济结构转型


人口红利是促进中国经济飞速发展的一个主要因素,房地产也是当中最大的获利者,大量的刚需消费基本靠着人口红利在支撑——两家三代攒出一套房的首付——这些年刚需市场里买房的80后,有几个首付是靠自己打工挣出来的?


这当中不能不涉及的是中国经济结构的转型,这使得我们父母一代这辈子基本没有类似于买房这样的大宗消费支出,才得以为下一代提供资金。同时,独生子女政策又保证父母可以用全部财力帮助一个孩子,父母一辈兄弟姐妹众多也变成了一项资金来源(借钱啊!)……总之,人口结构+经济结构的变化,为近十年的房地产发展提供了坚实的大市场。


人口红利还能吃多久?唱衰房地产的人估计是3-5年,但我相对乐观的估计是8-10年,因为接下来走入社会的90后依然有类似的状况,并且比80后更具优势——他们有积累更丰厚的父母——60后。


在我看来,60后是建国以来最幸运的一代:大饥荒和wen革时还小,上学时学校已逐步复课,考大学时高考恢复,毕业了赶上改革开放,工作几年迎来中国经济第一个活跃期和充满不可复制的财富积累机会的90年代。这也可以解释为什么“富二代”现象更多地出现在90后身上。所以,我判断8-10年之间,90后在房地产市场上的购买力仍然会支撑起一个巨大繁荣的行业。



4、可怕的传统置业观念+物质社会下的不安全感+残疾的租房市场建设


讨论上一条的时候,我们忽略了一件事情:父母一代积累的财富用在孩子身上,为什么一定或者首先是买房子呢?在第1、2两条里,我们说热钱去买房是因为没有其它理想的、大宗的投资渠道以及掌握热钱阶层的局限性,但对于80、90后来说,恐怕花钱的方向还有很多。所以我们不得不面对本条标题这三个原因。


作为一个上千年以农立国的国家,中国人自古以来就有着狂热的土地和家产崇拜症,“以末致财,以本守之”是根深蒂固的观念,经商挣了钱首先一定是买房买田,然后纳三妻四妾(和今天别无二致啊)。而中国经济发展到今天,文化已经严重落后而无法和经济匹配(CCP系统性的摧毁了中华文化),整个国家土豪化、物质化,女性的自我认知商品化,老百姓要靠一套房子带给自己最基本的生存安全感,终于导致了今天“没房子=没老婆”、“房子=人生成功标尺”等观念自主不自主的成为全社会的共识,构成刚需市场如此巨大的一个重要理论基础, 也使中国成为年轻人最热衷买房的国家。有兴趣的可以查一查各国首次置业的年龄调查,我记得07年看过的一个数据,美国居然是42岁,欧洲也普遍在30岁以上。


这时一定有人会说,我也想以后买房,我能顶得住父母和社会舆论的压力,但租房住的品质实在太低(四处搬家、随意涨价、没有归属和安全感),这就要说到本条的第三项了。 中国ZF一直以来忽略着对租房市场的培育、建设和管理(仅仅是廉租房完全不够,需要着眼于不同财富阶段、不同价位和品质的所有租房细分市场),在中国ZF的诸多不作为中,我认为这是最丧尽天良的一项。置业观念不是不可以改变的,改变的前提是有足够稳定的租房环境。发达国家的ZF实际上在这一方面都做得比较到位,保证国民可以在一辈子不买房的情况下也不会有居住的困扰。我曾在这个回答 全面征收房产税是否会导致房价大跌?中也提到过:

一个价格合理、信息充分、管理有序的租房市场,其实是最有效减少刚需客群的大水池,将从很大程度上调节地产市场的供需关系。

一个成熟的租房市场对中国社会面貌的改变会是难以估量的:年轻人的财富和消费能力得到巨大的释放,不再承受着巨大的生存压力,用更多的金钱和精力去追求更多非物质的生活,对财富、工作、生活的认识、甚至整个世界观都会发生改变。这种情况下形成的新兴中产阶级什么都能做的出来,大家发挥想象吧。


【1月14日补充】租房管理的具体问题有朋友提出来了,热烈欢迎来讨论 如果国家打算改善现在混乱的租房体系,你认为有哪些应该做的?如何借鉴美国、德国等国家的经验。



5、投资拉动型经济+城镇化+有中国特色的ZF职能


最后,说回到卖地的问题。

其一,中国经济三驾马车,投资、消费和出口中,消费的增长比较给力但没有什么质变,出口这几年是最受影响的,应该说始终还是大量依赖于投资这一项(比如wen的四万亿怪胎)。而城镇化则是能够拉动巨大投资的行为,其中又属房地产是主力部队,其上下游整个产业链巨大,覆盖面广,这也是为什么房地产是支柱产业的原因。所以ZF卖掉一块地,不仅仅是获得土地财政收入,也同样是对地方经济整体的一个拉动,一个地产可以养活的人太多太多了。


其二,我们说两税制以后ZF缺钱,卖地才能提高财政收入。问题来了——为什么ZF要收那么多钱?因为ZF花钱的地方多呗——为什么花钱的地方多?因为 他们管的宽,没人管他们。这其实进入一个更大的命题了:充分的市场经济甚至现代文明下ZF应该扮演怎样的角色?我们羡慕很多“小ZF”国家,因为人家的ZF基本只提供必要的服务,以及管理一些国计民生的产业,大部分都交给企业来做,不仅市场运转效率高,ZF需要花的钱也少,相对也更加清廉。而我们的ZF肩负太多的职责,触角广且深,更不要提养着多少无用的机构和闲人以及腐败的消耗了。



回到文章最初,我之所以用”中国房价现象“而不是题主所说的”中国房价高“,是因为这从来不是个孤立的问题,是中国经济走到今天这一步一个几乎必然的结果,这背后是中国的经济发展方式、特色的市场经济、文化和社会观念、ZF职能定位等一些基本要素共同结果的一个现象 而已。一个让全世界都乍舌的高速发展国家,一个让西方打破意识形态束缚不得不贴过来的经济体,总会练出点儿邪门的东西来,欧阳锋都静脉逆行了,东方不败都挥刀自宫了,房价有点儿吓唬人又算得了什么呢。



【2017年3月31日更新广告】

我的第一场live准备好了。我将会以合作嘉宾的形式,和@羊迪一同就买房的话题和大家分享自己的看法。
时间:2017年4月22日
主题:“我该买房么?”
欢迎围观:

https://zhuanlan.zhihu.com/p/26117337

使用 Elasticsearch 的 44 条建议

$
0
0

在搜索业务上摸爬滚打3年,使用的Es版本也从1.x升级到了5.x,扮演的角色也逐渐从Es的使用方变为维护方,这里大致汇总了使用Es过程中踩的一些坑以及一些注意事项,也会穿插一下我们的解法。 



01

es中建索引是指创建一个保存数据的目录,用于保存倒排索引,索引创建之后是不可变的(Immutable),只允许新增字段。

因为lucene中field是带类型的,不同类型的字段进入倒排索引后会经过压缩,long/int/short占用的字节长度不一,如果修改字段类型,很可能导致从索引文件中解压字段失败,更不要提string=>int之类的变换了;此外es会将文档id压缩存储(有序列表->差值形式->压缩),并通过跳跃表来提高查询性能,倒排索引查出term对应的doc_id集合,再用doc_id取field value用于排序或聚合,其实是lucene的实现,所以要变更索引文件代价很大,需要解压=>变更=>压缩,大量的CPU和io操作。



02

es字段是否索引只能在创建索引时配置,不能在字段创建后再给字段“加索引”。

lucene的字段有indexed的属性,如果设置false则不会写入倒排索引文件,如果要后期将某个字段改为indexed,相当于把整个索引重建一次,既然索引都要重建,也就没必要提供类似的功能了。



03

索引字段有为“索引(indexed)”和“存储(stored)”两个属性,只有被“索引”的字段才能在查询/排序条件中使用,只有被“存储”的字段才能在请求的时候返回字段内容。

同上,另外要说明的是,如果字段没有被设置为stored,则这个文档在update后会丢失该字段,因为Es的update操作其实是从索引文件中取到stored的原始值,合并后index回去,如果没有存储该字段内容,新生成的文档也不会带有该字段,index后原文档被覆盖也就丢失该字段了。



04

必须保证索引字段都存储(stored)才能使用update操作,update原理是先从索引中get到原文档内容,然后与传入的欲更新字段合并,作为一个新的文档index回去,如果有字段不是stored,那么update之后该字段就丢失了。

同03条注释。



05

为了提升查询性能,索引文件被设计为不可变文件(便于如跳跃表之类的访问性能优化),在生成后不会发生变更,通过Es看到的数据均为某个时刻引擎打开的快照数据,为了能做到反应数据变化,会有刷新时间refresh_interval的概念。

这里会反复提到近实时(NRT)的概念,希望大家在使用过程中一定明确一点,Es不是一个真实时的存储服务,务必不要用在实时业务场景中。

假定某个时刻为t,t时刻引擎打开的快照数据也就是t时刻的全部有效段文件,t时刻之后写入的数据是不可见的,这些数据会生成新的段,在 t+refresh_interval时刻,Es会重新扫描并打开该时刻的全部有效索引文件,以此近实时的反应数据变化。



06

es还无法做到资源二级调度(共享线程池/缓存区等,无法按索引隔离资源),所以如果集群内某一个索引发生大量慢查询或者污染缓存区(用低复用率内容踢出其他索引高复用率缓存),会导致search线程池满或者引起gc,阻塞集群内其他索引的响应。

如题,重要业务最好保障物理隔离。



07

es每次refresh需要重新打开所有索引文件(需要解压/刷缓存等),如果索引文件较多且更新频繁,每次refresh的开销会比较大,使机器负载升高,影响查询rt,所以更新频繁的大索引设置的刷新时间会限制到5s以上(实时程度下降),要提高实时性,必须减小索引大小。

Es默认是1s刷新,如果索引到达千万级别且更新频繁,rt可能会上升到100ms级别,算算qps是不是很虚呢。



08

es有window size的概念(from+size),每次查询先从每个shard中取window size条数据,然后在集群中某个节点汇聚数据,排序后取size条数据返回,假设有n个shard,有效数据占比=size / (n * (from+size)),故Es查询时会限制window size,避免产生过多垃圾数据加重gc和IO负担。

如题。



09

因为索引文件是不可变的,要反应数据的变化需要一次刷新操作来重新扫描并加载新的索引文件,所以任意时刻查询的数据都是t时刻(扫描并加载索引文件的时刻)的快照数据,刷新时间的长短决定了数据的近实时(nrt)程度。

原因见第05条,刷新时间默认1s,可以通过settings API动态调整,一般建议5s,Es/Solr都是nrt(近实时)的服务,务必明确,不要当实时存储来用。



10

es有translog,也就是write ahead log,用来保障数据的故障恢复,写操作都必须保证写translog成功,避免服务挂的时候数据丢失。

translog其实也不是绝对的靠谱,有async和request两种模式,如果是async模式(Es1.x只有这个模式),会在内存中积累一定大小或到一定时间后触发flush操作来持久化到磁盘,如果掉电还是有丢数据的可能性,得通过主从副本来保障数据的持久化,如果是request模式(Es5.x默认)则要靠谱的多,每次写操作都会将translog落盘,但是很明显会导致磁盘io压力上升,依赖各自的实际业务场景来取舍。



11

search操作是检索searcher打开的快照数据,所以search是个近实时操作,取决于快照数据的近实时程度;不同于search,es的get操作可以在保证必要条件的情况下做到真实时,可以从translog中提取文档,拿到最新写入的文档数据。

其实get也有refresh和realtime的,要真实时必须指定realtime为true(默认),Es会通过检查versionMap(存储两次刷新间隔中写入数据的元信息)中是否有当前文档的_uid来判断是否触发一次刷新操作(Es是通过searcher来get到文档的,translog只是用来取source),refresh参数用来提示get操作前是否一定进行一次刷新操作(可以达到真实时目的,但是不建议开,性能损耗太大,用realtime就可以达到目的了),另外必须指定preference为_primary,否则还是可能会get到旧版本数据,比如写入时没有指定wait_for_active_shards,默认只要_primary存活即可,且不保证写入到全部副本,如果副本短时上下线就有可能会导致数据延迟。



12

在假设正常情况下并发更新概率很小的前提下,为了性能考虑,es通过乐观锁解决文档并发更新问题,创建文档时如果不设置version,默认初始version=1,之后每次update时version自增;如果要重置version,只能通过index操作并设置force=true,来强制重置文档version。

如题,另外Es6.x开始已经在考虑取消force参数了。



13

es原生不支持在update时设置version(理论上是可以实现的,给开发组提了个issue:https://github.com/elastic/elasticsearch/issues/25996,但是没通过),实在要做可以在业务程序中一定程度上模拟带version更新操作。

Es的更新操作就是先get到最新文档,然后与传入的文档合并后再index回去,同时标记原文档为deleted,这个过程就可以将自增的版本号设置为外部版本号。

还有要注意的一点是VersionType尽量不要设置为新version>=原version,可能会导致并发更新时的多个请求的数据有一个或多个被覆盖。



14

es1.x版本默认date类型处理会在format parse失败后尝试用long.valueOf来转换,假设字段配置为date类型,format为YYYY-MM-dd HH:mm:ss,那么传入一个"12345"的string类型,es1.x版本是不会报错的,会把"12345"转成long再转成UTC时间;es5.x版本已经修复这个问题。

如题。



15

es的source是单独作为一个字段存储的,而且是保持传入的样式原样保存,假设字段A类型为long,如果传入的doc={A: "12345"},即使A为string类型也是可以正确录入的,但是返回的source中字段A还是保持string形式"12345",不会转换成配置的long类型。

Es作为存储来说更像是一个文档数据库,下文有提到。



16

es版本执行写请求时,如果源文档设置的version与已存在的文档冲突(默认策略provided version > stored version算成功),会报version conflict异常,即使是在index或者create操作时显式设置version,也有可能会抛出版本冲突异常。

如题,除非修改VersionType为gte(设置force=true也行,不建议做,会强行覆盖原数据),否则有并发更新时,如果别的请求先于你的更新,乐观锁检查就会失败。



17

update时可以通过设置retry-on-conflict来降低版本冲突异常出现次数,在遇到version冲突时,引擎会根据设置的retry次数(默认是0)来自动重试,如果重试后更新成功则返回成功,当然在极端情况下(重试n次之后依然冲突)还是会抛version conflict异常。

注意,设置retryOnConflict请保证此次操作是幂等的,如果不是,还是在业务程序内处理重试吧,比如一个带状态的字段更新,A请求更新为1,B请求更新为2,B先于A更新成功,A报conflict异常,如果设置了重试,最终的更新结果是状态变为1,sad。



18

es的match操作不走缓存,即使索引量较小(几十万文档),一次匹配全文档的match操作(match: {title: xxx})至少有几十万次计算(与文档数正相关),如果qps很高,同样会因为集群CPU过高而阻塞search线程池,导致集群无响应。

如题,match操作每次都会实打实的计算,耗CPU,搜索应用务必保证基础的结果缓存(需要自己实现)可用,减少match请求次数。



19

translog有request落盘的方式(每次写数据都会落盘)和async方式(batch,累积一定量数据后落盘),es5.x默认使用的是request方式,也就是优先保障数据不丢;但es1.x只有async方式,以性能优先,每隔一段时间(默认5s)检查是否需要将translog落盘,在机器掉电情况会有数据丢失风险。

translog的持久化参数主要有三个: index.translog.durability控制通过request还是async方式持久化到磁盘,如果通过async方式,index.translog.flush_threshold_size控制堆积多少数据后触发一次flush操作,index.translog.sync_interval控制间隔多少时间出发一次flush操作。



20

如果Es应用场景数据更新很频繁,新对象生命周期很短,如果young区分配比较小,可能会造成大量短生命周期的新对象涌入old区,引起full gc导致集群不能正常响应(视old gc的算法而定,如果是g1则full gc会退化成serial gc),需要控制young区在合适的比例,但是也会造成ygc的停顿时间变长,表现为比较明显的rt毛刺。

视gc算法而定,g1算法的ygc也会stw,cms算法在heap超过16g情况下表现不是很好。



21

操作es常见的三种异常:DocumentAlreadyExists(文档已存在,有并发create操作易发生),VersionConflict(版本冲突,有并发update操作易发生),DocumentMissing(文档不存在,有并发的create/update/delete操作时易发生)。

Es5.x取消了DocumentAlreadyExists异常,也将其视为VersionConflict。



22

should查询子句在query和filter中语义不同,在filter中should条件必须至少满足一个(is or not的问题),在query中如果同时存在must或must_not条件则不要求should条件必须满足一个(how well的问题,should条件满足会提高查询得分_score),如果要求query中should与filter的语义类似,可以设置bool字句中的minimum_should_match参数为1解决。

bool query中的should默认不做必须命中要求(只有should条件除外),bool filter中的should必要至少命中其中一个子条件。



23

推荐将不用来计算相似度的字段的norm属性关闭,比如时间/状态等仅用来filter或aggregation的字段,可以减小索引大小,默认会用1 byte/doc来存储字段的norm值,即使某个文档根本没有对应的字段。

tf/idf是经典的相似度计算模型, 可以用来理解相似度计算,一个查询先分解为n个term,计算每个term的tf/idf值(其中就有norm),然后以该值作为空间向量权重,形成n维向量空间,再应用余弦定理计算n维空间内查询词与文档的相似度,得到文档匹配分。

Es5.x默认使用bm25作为相似度计算方法了。



24

Es的核心是倒排索引,也就是term -> doc_id的形式,如果是分词字段,索引过程是先分词,然后将分词后的term与文档id结对成为倒排索引文件,假设索引字段为title=“测试商品”,采用bigram的分词方式,那么最终的倒排索引是"测试"=>id / "试商"=>id / "商品"=>id;match查询则是将查询词分词后转为term,再用term去和倒排索引进行"精确"匹配,比如查询"商品",分词后term="商品",和倒排表精确匹配得到doc_id即是查询结果,如果搜索"商",分词term="商",倒排索引中是没有这个term的,因此查询结果为空;搜索引擎的match查询并不等同与mysql的like查询,如果要搜索类似mysql的"商品%"条件,Es的表现是不太好的。

Es没有B树索引,prefix查询是通过状态机实现的。

match操作能不能搜到结果主要看存储字段分词后的term能不能与查询条件分词后的term匹配上,假设"美观建筑真好看"分词后得到"美观"/"建筑"/"真"/"好看"/"好",如果用term搜索"真好看",那么在倒排表中无法找到对应的词条(term不分词),找不到结果;如果用match搜索"真好看",那么也会被分词为"真"/"好看"/"好",这时就可以在倒排表中找到对应的词条了;再比如搜索"观建",假设分词后得到"观"/"建"/"观建",虽然字段中存在这几个字符,但是倒排表中并没有,所以也找不到结果。



25

match_phrase匹配比较严格,在全匹配的基础上还要求字符顺序一致,可以有效提高查询准确率,但是为了保证召回率,一般情况下会搭配一个半匹配match使用,例如:"bool":{"should":[{"match_phrase":{"title":"test"}},{"match":{"title":"test"}}]}。

比如"漂亮又美观的建筑",通过match查询"漂亮 建筑"可以得到结果,但是通过match_phrase查不到,因为"漂亮"和"建筑"之间的position_gap>1,可以通过slop参数控制position_gap的大小。



26

使用scan操作时需注意,es1.x版本init scan不会返回hits,只有在next scroll时才会返回,循环调用scan时注意控制条件,第一次应当判断totalHits>0,后续可以用hits.length>0判断。

scan操作只有Es1.x版本支持,Es5.x版本只提供scroll。



27

es1.x版本scroll和scan是不同的操作,在scan时如果设置size=10,则返回size num_of_shards条数据,假设索引分了5个shard,共返回50条数据,而普通scroll操作时如果设置size=10,则最多只会返回size条数据,即使索引分了5个shard,也只会返回10条数据,但是普通scroll效率没有scan高;es5.x对默认排序的scroll操作做了定向优化来替换scan,因此只保留了scroll。

按照段内顺序(doc_id)直接出结果,减去聚合排序步骤,但是得到的结果可以被认为是无序的,doc_id按照写入顺序排列。



28

es的数值类型都是带符号的,尽量将数值字段值控制在signed long范围内[-2^63]~[2^63-1],否则只能用分拆方法或者用string类型来存储,但是会使排序或者范围查询达不到预期效果。

对于java不是很熟悉的同学更需注意,不要因为数值范围限制而导致重建索引。



29

索引mapping默认关闭了自动映射功能,写入不在mapping中的字段会抛出异常,原因是自动映射是根据第一次遇到的字段内容来推断类型的,假设字段A是商品名称且事先未配置mapping,那么如果第一个写入es的doc中字段A内容是"12345",es就会给字段A定义为long类型,就不符合预期了。

推荐将mapping中的dynamic设置为strict,在出现未配置的字段时抛出异常,避免因为字段自动映射错误而导致重建索引(原因见01条)。



30

es通过任务队列来削峰限流,默认search queue=1000,index queue=200,如果短时流量过高导致队列溢出,就会抛出EsExecutionReject异常,而任务队列都是全集群共享的(某索引大量占用队列就会导致其他索引占不到资源,而无法响应),如果多索引共享集群,尽量能控制每个索引的写入速率。

如题,另外最好也能控制每个索引的match qps,避免过多match导致CPU资源耗尽。



31

慢查询比较多的索引也同样会堵塞es的search任务队列(典型的如单一的海量数据索引,短时一个波峰很容易导致es抛Reject异常),因此线上业务最好根据自身应用场景开启索引的慢查询日志。

Es默认的慢查询阈值有点大(秒级),一般偏存储类的应用能接受的rt在200ms以内,线上业务需要做好慢查询优化,比如没有合理使用用filter缓存/terms条件内id过多/多次sort/match长度过长/索引数据量过大等。



32

Es的Java API需要通过捕捉运行时异常来处理异常操作。

如题,写业务代码最好加上try catch代码块。



33

es的增改删(cud)操作本质都是lucene的index/delete两种操作的组合,update操作就是先取出stored的原文档字段,与本次操作数据合并后重新index回索引,然后delete原文档,也因此写操作index queue其实就包含了所有增改删的任务。

lucene暴露的接口是addDocument/updateDocument,而addDocument接口还是调用updateDocument方法,不要只看名字,其实updateDocument就是先写入新文档(不是partial update),然后标记老文档为deleted状态。



34

Es是一个近实时(NRT)的服务,索引的刷新时间(refresh_interval)控制了文档数据的延时程度,如果设置了-1,则新增文档或被更新的文档必须等到索引的translog达到commit条件触发刷新操作后才能可见。

也就是达到index.translog.flush_threshold_size配置的大小,进行一次lucene commit操作,生成新段并打开,注意不要混淆索引的flush操作和translog的fsync操作。



35

因为lucene在删除文档时只是标记删除,标记删除的doc_id在查询出候选结果时被用来过滤,标记删除的文档只有在merge阶段才会被物理删除,真正释放磁盘空间和机器资源,一般更新比较多的索引残留的deleted docs会比较多(更新就是index+delete的组合),在实际的搜索过程中,标记删除的索引文档会和普通文档一样会被加载到内存并纳入计算,也会被decode到doc_id,撑大倒排索引,这直接影响到索引的读写性能。

Es的删除操作(也就是lucene的删除操作)是先标记删除,并单独在一个文件中存放标记删除的doc_id,用于在查询时将删除文档过滤掉;删除的文档只有在段合并(merge)阶段通过重写索引文件才会物理删除

更新太频繁导致merge跟不上新产生的标记删除文档,可以通过deleted文档比例来判断更新操作是否过于频繁,尽量合并多个字段的更新为一次请求。



36

Es带sort的查询需要在倒排索引匹配结束后,拿到索引文档的id_set(此时无序),然后通过id获取对应字段的值(fielddata/doc_value),通过优先级队列或者其他容器来计算顺序,建议能少做sort就少做。

如题,尽量减少带文档字段排序的请求,如果有多个字段排序,避免第一字段值太单一(第一排序相等,降级到第二字段排序来确定文档顺序)

另外尽量避免用string/array/nested等高级类型来做排序,string排序是字典序,多值字段排序会有更多运行时计算,会拖慢查询影响时间。



37

Es的_score排序表示按照查询匹配分排序,需要注意两点:1. 比如term之类的精确匹配其得分是固定值的;2. 模糊查询match条件返回的得分经过normalize之后也可能会得到相同的得分,得分相同的查询结果会在结果展示上表现出一定的随机性,建议在_score之后加上第二排序条件,在匹配分相同时保证顺序固定,比如:[{"_score":"desc"},{"_id":"desc"}]。

如题,另外需要注意的是,如果查询的意图是match,匹配度最高在前,但是又在sort条件中指定了字段排序,比如time:desc,那么得到的结果是满足match匹配度(默认75%)前提下time越新的越前(一般是不满足期望的)。解决方法可以是设置匹配度100%,要求全部文字匹配,或者用上面提到的方法,将_score排序放到第一位。



38

close索引的时候最好先把alias去掉,如果一个alias包含多个索引,其中一个索引带着alias被close掉,用这个alias来检索会失败。

Es可以通过一个alias来关联多个真实索引,可以实现比如按天切分的索引当作单一索引使用,但是如果alias包含了closed状态的索引,Es不会跳过这个索引,而是会抛出IndexClosed异常。



39

使用了nested字段类型的索引,其创建某个文档,如果其中嵌套了2个子文档,加上父文档,总共会创建2+1个文档。

使用nested字段类型如果嵌套文档过多,会导致索引极速膨胀,影响读写性能,使用嵌套字段务必先了解清楚业务应用场景。



40

lucene 6.x使用有限状态机FSA来提高模糊查询性能(fuzzy/prefix),但是实现有缺陷,使用了递归来判断状态机是否有限状态,如果前缀查询输入了一个长字符串(状态机很大),在调用Operations.isFinite方法时会导致栈溢出StackOverflow异常,使得执行此查询的索引的shard所在进程直接退出,Es6.x版本修复,6以下版本建议限制查询长度及正则查询,同时控制索引shard个数,避免全集群机器全部宕机。

lucene内部用了一个递归操作来判断状态机是否有限,如果是个无限状态机或者状态机很大,递归太深就会导致栈溢出。。sad。



41

es5.x版本在update时会判断更新前后的值是否有变化,如果欲更新字段的新值与已存在的值一致,那么会跳过实际的写操作直接返回OK,所以如果发现更新返回成功,但是version没有自增,可以检查是否欲更新字段的值与已存在的值相同。

如果发现更新后version没有变化,可以check一下是否此类情况,如有依赖version自增的业务,这点更是务必明确。



42

Es作为存储更像是个文档数据库,存的是个json,返回的数据格式也是json反序列化时自动推测的,不会按照预置的mapping字段类型返回,Es设置的mapping对存储内容无效,只是在建索引时类型检查/转换用。

Es的_source内部是lucene的一个indexed=false/stored=true的字段,之所以单独存放到一个_source字段,猜想是为了提高存储内容的访问速度,如果是用lucene索引字段的stored内容,取一次source就需要遍历全部fields了。



43

推荐根据字段的取值来设置字段类型,如小于7个枚举值可以用byte,减少索引文件的overhead,也避免在Es中存储大容量字段,即使不用来索引;可以不索引的字段就不索引(indexed: no),可以减小倒排索引文件,提高读写性能。

lucene生成的索引文件在存储时会根据字段类型占用的字节长度进行补齐,方便跳跃访问,用精确的字段类型可以减少io上的虚耗。

Es中存储的大字段也会在段文件中保存(段文件有很多不同用途文件组成),会影响读写性能(merge操作会变多,也变慢,访问频率如果很高也会导致内存中不断生成大对象)



44

分词后的字段会变成小粒度的词条,比如"美观的建筑"分词后可能会变成"美观"/"建筑"(视分词算法而定),不会保留原始内容("美观的建筑"不会进入倒排表),也就无法用term条件来查询了,只能用match。

如果需要同时对某个字段进行多种分词(包括不分词),可以通过multi-field来解决。

分词问题详见第24条。




这里列了遇到比较的一些点,不是全部,更多的细节还需要深入挖掘。


欢迎大家长按关注跳跳爸的微信公众号:


代替那些「用完就删」的 App,试试这 9 个实用的网页小工具

$
0
0

很对人对于软件都有一种「收藏」的习惯,觉得这可能是一个工具就把它购买或下载放在那里,新鲜了两天就搁置在那儿,终究成了橱柜上的一个布满灰尘的摆设。其实很多时候我们可以换个思路,如果这个工具是在网页上,用的时候再打开,不用的时候就关闭,既不占用你电脑空间,也不受限于设备的系统,或许还能帮你省下不少的钱,今天少数派就为大家介绍一些实用而且有趣的网页工具。

Internet Speed Test

一个良好的网速大概会有 80% 的概率提高我们的生产力和执行力,糟糕的网速大概会有 99% 的概率影响我们的情绪。所以经常会有一些朋友频繁的测量网速,有的选择下载一款软件进行测量,有的随便找一个网站就将就了。而 FAST和  SPEEDTEST是两家「优雅」的测速站点,只点击一下 ► 按钮再稍等片刻,你的网速测试结果就会呈现在你的面前,无污染、零广告、完全免费。

相关链接: FASTSPEEDTEST

whiteboard

白板的用处有很多,打草稿,记录突如其来的灵感,或者玩玩你画我猜也是可以的, whiteboard就是这样的一个随开随用的白板网站。这个网站的构造非常简洁,工具只有画笔、文本框、橡皮擦,虽然工具简单,但几乎所有的操作都支持快捷键,无需你去工具中点来点去。如果你绘制的图像趋于一定的形状,例如圆形、矩形,它可以自动的转换为标准形状。绘制完成的白板,也可以通过右上角的「Share」分享给其他的人,而其余的人也可以进行编辑,而两边的画面也是同步的。除此之外,该网站也提供了 Slack 群组的插件,如果你们有用到 Slack,不妨添加这款插件试一试。

相关链接: whiteboard

在线 Markdown 编辑器

不知道前段时看了 《想学 Markdown?这篇文章帮你快速上手》之后有没有想尝试一下 Markdown 的冲动,对于还没选择到合适 Markdown 工具的时候,不如先用这款 在线 Markdown 编辑器体验一下语法,在这里左侧输入的文本内容都会实时的显示右侧和下侧,分别是 HTML 格式预览以及实时效果预览。但是在网站编辑的内容并没有提供保存到本地的入口,如果你需要请及时复制粘贴。建议只是作为临时备用方案或是体验方案,如需深度体验还是选择专门的 Markdown 工具。

相关链接: 在线 Markdown 编辑器

草料二维码

二维码在生活中可以说是非常常见了,从付款码到共享单车,随处可见。其实对于我们来说,不仅可以扫码当然也可以制作二维码,例如我们想分享某个网址,或者把我们的 Wi-Fi 提供给别人(可以用这个 Workflow)。而 草料二维码不仅给我们提供了制作二维码的途径,也为我们附上了一些「优雅」姿势。在这里你只需要输入的文本内容,在右侧选择二维码属性。可以选择直接使用模版图案快速美化,也可以使用旧版的美化器(功能齐全)来进行更细致的操作,例如选择背景前景图、颜色以及二维码状态。这样以来,不论你的二维码用在哪里,都再也不怕单调无味。

相关链接: 草料二维码

图片处理

图片在我们生活中的用处太多了,但时常我们也会因为图片的事情而苦恼。因为在不同的使用场景里,对图片的要求可能都不太一样,例如有的限制了大小,有的限制了格式。对于这些问题,我们其实不需要复杂了步骤,也不需要安装一些软件,只需要上传一下然后处理就可以了。对于图片的格式问题,你只需要在 Jinaconvert上选择你需要的格式类型,再将图片文件上传至即可。

相关链接: Jinaconvert

你在上传图片时因为大小而受到了限制,可以在 TinyPNG这个网站上进行压缩操作。该网站支持对  .png和  .jpg格式的图片进行压缩,只需要将图片拖拽至网站的窗口即可,一次性可以压缩 20 张,且质量非常不错。如果你非常喜欢它,也可以移步阅读  《TinyPNG 是我最喜欢的在线压图服务,现在有人给它做了 macOS 客户端》

相关链接: TinyPNG

Ringer

手机的铃声是不是从来没有更换过,可能是因为制作铃声的方法有那么点复杂,一步步的操作加上各式软件,或许就让你放弃了这个念头。其实,你只需要把各类格式的音乐源文件上传到  Ringer 上,选择选上铃声的开头结尾。最后选择 M4R 或是 MP3 就可以了,可以说是免费又快捷了。

相关链接: Ringer

Keyboard Layout Editor

Keyboard Layout Editor是一个键盘图纸设计的网站,它的作用可以说是非常的多。如果你刚上手一个软件,但是却无法记住它的全部快捷键,不如直接将快捷强的功能放置在图纸上,打印下来贴在桌边,帮助你记忆。如果你正常考虑一款机械键盘的配色,你可以在这上面选择相应的键位进行颜色的修改,最后看看整体的配色效果。它的自定义程度非常的高,在这里几乎可以编辑键位所有的参数,所以它究竟能起到什么样的作用,就看你如何利用它了。设计好的内容网站也提供了五种格式的文件方便用户下载,如果喜欢不妨加入到收藏夹里。

相关链接: Keyboard Layout Editor

Gifntext

还记得网上很火的「为所欲为」和「王境泽」吧,丰富的表情配上字幕,随随便便就是一个表情包。其实为 Gif 添加字幕也没有那么的困难,只需要将准备好的 Gif 文件上传到 Gifntext上,然后就可以对播放速度以及画面尺寸进行调节。于此同时,也可以自由的在时间轴中加入想要的字幕、图片或是涂鸦。网站最大可以上传 100M 的 Gif 文件,修改完成后创建的动图自动的进行压缩。

相关链接: Gifntext

如果你还有其他有意思的以及实用的网络在线工具,也欢迎在评论区留言推荐给大家!:tada:

互联网高可用架构技术实践

$
0
0

一、什么是高可用

高可用HA(High Availability)是分布式系统架构设计中必须考虑的因素之一,它通常是指, 通过设计减少系统不能提供服务的时间。

假设系统一直能够提供服务,我们说系统的可用性是100%。如果系统每运行100个时间单位,会有1个时间单位无法提供服务,我们说系统的可用性是99%。很多公司的高可用目标是4个9,也就是99.99%,这就意味着,系统的年停机时间为8.76个小时。

百度的搜索首页,是业内公认高可用保障非常出色的系统,甚至人们会通过www.baidu.com能不能访问来判断“网络的连通性”,百度高可用的服务让人留下啦“网络通畅,百度就能访问”,“百度打不开,应该是网络连不上”的印象,这其实是对百度HA最高的褒奖。

二、如何保障系统的高可用

我们都知道,单点是系统高可用的大敌,单点往往是系统高可用最大的风险和敌人,应该尽量在系统设计的过程中避免单点。 方法论上,高可用保证的原则是“集群化”,或者叫“冗余”:只有一个单点,挂了服务会受影响;如果有冗余备份,挂了还有其他backup能够顶上。

保证系统高可用,架构设计的核心准则是:冗余。有了冗余之后,还不够,每次出现故障需要人工介入恢复势必会增加系统的不可服务实践。所以,又往往是 通过“自动故障转移”来实现系统的高可用。接下来我们看下典型互联网架构中,如何通过冗余+自动故障转移来保证系统的高可用特性。

三、常见的互联网分层架构

enter image description here

常见互联网分布式架构如上,分为:

  • (1)客户端层:典型调用方是浏览器browser或者手机应用APP
  • (2)反向代理层:系统入口,反向代理
  • (3)站点应用层:实现核心应用逻辑,返回html或者json
  • (4)服务层:如果实现了服务化,就有这一层
  • (5)数据-缓存层:缓存加速访问存储
  • (6)数据-数据库层:数据库固化数据存储

整个系统的高可用,又是通过每一层的冗余+自动故障转移来综合实现的。

四、分层高可用架构实践

1. 客户端层->反向代理层的高可用

enter image description here

客户端层反向代理层的高可用,是通过反向代理层的冗余来实现的。以nginx为例:有两台nginx,一台对线上提供服务,另一台冗余以保证高可用,常见的实践是keepalived存活探测,相同virtual IP提供服务。

enter image description here

自动故障转移:当nginx挂了的时候,keepalived能够探测到,会自动的进行故障转移,将流量自动迁移到shadow-nginx,由于使用的是相同的virtual IP,这个切换过程对调用方是透明的。

2. 反向代理层->站点层的高可用

enter image description here

反向代理层站点层的高可用,是通过站点层的冗余来实现的。假设反向代理层是nginx,nginx.conf里能够配置多个web后端,并且nginx能够探测到多个后端的存活性。

enter image description here

自动故障转移:当web-server挂了的时候,nginx能够探测到,会自动的进行故障转移,将流量自动迁移到其他的web-server,整个过程由nginx自动完成,对调用方是透明的。

3. 站点层->服务层的高可用

enter image description here

站点层服务层的高可用,是通过服务层的冗余来实现的。“服务连接池”会建立与下游服务多个连接,每次请求会“随机”选取连接来访问下游服务。

enter image description here

自动故障转移:当service挂了的时候,service-connection-pool能够探测到,会自动的进行故障转移,将流量自动迁移到其他的service,整个过程由连接池自动完成,对调用方是透明的(所以说RPC-client中的服务连接池是很重要的基础组件)。

4. 服务层>缓存层的高可用

enter image description here

服务层缓存层的高可用,是通过缓存数据的冗余来实现的。 缓存层的数据冗余又有几种方式:第一种是利用客户端的封装,service对cache进行双读或者双写。

enter image description here

缓存层也可以通过支持主从同步的缓存集群来解决缓存层的高可用问题。

以redis为例,redis天然支持主从同步,redis官方也有sentinel哨兵机制,来做redis的存活性检测。

enter image description here

自动故障转移:当redis主挂了的时候,sentinel能够探测到,会通知调用方访问新的redis,整个过程由sentinel和redis集群配合完成,对调用方是透明的。

说完缓存的高可用,这里要多说一句,业务对缓存并不一定有“高可用”要求,更多的对缓存的使用场景,是用来“加速数据访问”:把一部分数据放到缓存里,如果缓存挂了或者缓存没有命中,是可以去后端的数据库中再取数据的。

这类允许“cache miss”的业务场景,缓存架构的建议是:

enter image description here

将kv缓存封装成服务集群,上游设置一个代理(代理可以用集群的方式保证高可用),代理的后端根据缓存访问的key水平切分成若干个实例,每个实例的访问并不做高可用。

enter image description here

缓存实例挂了屏蔽:当有水平切分的实例挂掉时,代理层直接返回cache miss,此时缓存挂掉对调用方也是透明的。key水平切分实例减少,不建议做re-hash,这样容易引发缓存数据的不一致。

5. 服务层>数据库层的高可用

大部分互联网技术,数据库层都用了“主从同步,读写分离”架构,所以数据库层的高可用,又分为“读库高可用”与“写库高可用”两类。

  • 服务层>数据库层“读”的高可用

    enter image description here

服务层数据库读的高可用,是通过读库的冗余来实现的。

既然冗余了读库,一般来说就至少有2个从库,“数据库连接池”会建立与读库多个连接,每次请求会路由到这些读库。

enter image description here

自动 故障转移:当读库挂了的时候,db-connection-pool能够探测到,会自动的进行故障转移,将流量自动迁移到其他的读库,整个过程由连接池自动完成,对调用方是透明的(所以说DAO中的数据库连接池是很重要的基础组件)。

  • 服务层>数据库层“写”的高可用

    enter image description here

服务层数据库写的高可用,是通过写库的冗余来实现的。

以mysql为例,可以设置两个mysql双主同步,一台对线上提供服务,另一台冗余以保证高可用,常见的实践是keepalived存活探测,相同virtual IP提供服务。

enter image description here

自动 故障转移:当写库挂了的时候,keepalived能够探测到,会自动的进行故障转移,将流量自动迁移到shadow-db-master,由于使用的是相同的virtual IP,这个切换过程对调用方是透明的。

五、总结

高可用HA(High Availability)是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间。

方法论上,高可用是通过冗余+自动故障转移来实现的。

整个互联网分层系统架构的高可用,又是通过每一层的冗余+自动 故障转移来综合实现的,具体的:

  • (1) 客户端层反向代理层的高可用,是通过反向代理层的冗余实现的,常见实践是keepalived + virtual IP自动故障转移。
  • (2) 反向代理层站点层的高可用,是通过站点层的冗余实现的,常见实践是nginx与web-server之间的存活性探测与自动故障转移。
  • (3) 站点层服务层的高可用,是通过服务层的冗余实现的,常见实践是通过service-connection-pool来保证自动故障转移。
  • (4) 服务层缓存层的高可用,是通过缓存数据的冗余实现的,常见实践是缓存客户端双读双写,或者利用缓存集群的主从数据同步与sentinel保活与自动故障转移;更多的业务场景,对缓存没有高可用要求,可以使用缓存服务化来对调用方屏蔽底层复杂性。
  • (5) 服务层数据库“读”的高可用,是通过读库的冗余实现的,常见实践是通过db-connection-pool来保证自动故障转移。
  • (6) 服务层数据库“写”的高可用,是通过写库的冗余实现的,常见实践是keepalived + virtual IP自动故障转移。

末了,希望文章的思路是清晰的,希望大家对高可用的概念和实践有个系统的认识,希望对得住这20块的打赏,however,未尽事宜后续小范围讨论沟通。


Viewing all 15900 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>