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

三种方法实现移动端HTTPS的加速和省电

$
0
0

作者:王继波
野狗科技运维总监,曾在360、TP-Link从事网络运维相关工作,在网站性能优化、网络协议研究上经验丰富。
野狗官博: https://blog.wilddog.com/
野狗官网: https://www.wilddog.com/
公众订阅号:wilddogbaas

图片描述
HTTPS网站的普及使大家更加关注HTTPS性能优化,一般做HTTPS优化可能只是针对PC端,在移动端的效果并不理想。去年Google就已经在移动端做了HTTPS的性能加速,为Android平台的Chrome浏览器增加了一个新的TLS加密套件:ChaCha20-Poly1305,这是专门为移动设备推出的加密套件。接下来我们深入探讨如何使用ChaCha20-Poly1305加密套件实现HTTPS移动端加速和省电。

下图是在iPhone Chrome上打开Google日本网站后的加密信息截图。

图片描述

野狗WildDog已经全站支持在移动设备上更高性能、更省电的加密套件ChaCha20-Poly1305。下面是在Chrome上打开野狗官网的加密信息截图。

图片描述

为了能够更好的了解ChaCha20-Poly1305,先简单介绍对称加密和AES-NI。

对称加密与AES-NI

对称加密

在HTTPS握手过程,通过非对称加密协商出对称加密密钥,然后使用对称加密对双方通信的数据内容进行加密。非对称加密是服务器性能的开销是巨大的,通过Session Resume等方法可以进行加速。常见的非对称加密算法有RSA、ECDHE等。

在协商出对称加密密钥后,HTTPS中所有数据内容通信的加密都使用对称加密进行。对称加密分为流式加密和分组加密。

  • 常见的流式加密算法有:RC4,ChaCha20-Poly1305。

  • 常见的分组加密算法有:AES-CBC,AES-GCM。

RC4由于存在严重安全漏洞,已经基本不再使用;AES-CBC容易遭受BEAST和LUCKY13攻击,使用也逐渐减少,AES-GCM是它们的安全替代,AES-GCM也是目前最为流行的对称加密算法。

安全风险可参看ssllabs上的相关文章:
https://community.qualys.com/blogs/securitylabs/2013/03/19/rc4-in-tls-is-broken-now-what

AES-NI

AES-GCM解决了对称加密存在的安全问题,但带来了性能问题。为此,出现了AES-NI(Advanced Encryption Standard New Instruction)。AES-NI是Intel和AMD微处理器上x86架构的一个扩展,可以从硬件上加速AES的性能,目前在服务器和PC端,CPU对AES-NI的支持率已经非常普及。

测试结果:服务器开启AES-NI后,性能提高了5-8倍左右,这与Intel官方公布的数据基本是一致的。

图片描述

测试方法:

可以使用OpenSSL测试也可以使用其他SSL库测试,因为所有SSL库都支持AES-128-GCM。

图片描述

关于AES-NI的指令集,推荐查看Shay Gueron编写的《Intel 高级加密标准 (AES) 指令集 (2010)》。 https://software.intel.com/en-us/articles/intel-advanced-encryption-standard-aes-instructions-set

ChaCha20-Poly1305优势何在?

Google推出新的加密套件并在所有移动端的Chrome浏览器上优先使用原因:

  1. ChaCha20-Poly1305避开了现有发现的所有安全漏洞和攻击;

  2. ChaCha20-Poly1305针对移动端设备大量使用的ARM芯片做了优化,能够充分利用ARM向量指令,在移动设备上加解密速度更快、更省电;

  3. 更加节省带宽,Poly1305的输出是16字节,而HMAC-SHA1是20字节,可以节省16%的overhead消耗。

通过实际的测试数据来看看ChaCha20-Poly1305在移动端使用的优势。

测试一:

在支持AES-NI扩展的设备上,AES加密的性能优势是明显的。 目前最为常用的对称加密AES-128-GCM的性能是ChaCha20-Poly1305的近5倍。

图片描述

由于原生的OpenSSL目前还不支持ChaCha20-Poly1305,通过编译LibreSSL源码(最新源码下载地址: http://ftp.openbsd.org/pub/OpenBSD/LibreSSL)来进行测试。

测试方法:

进入到编译后的LibreSSL目录,通过下面的命令测试。

./apps/openssl/openssl speed -elapsed -evp chacha
./apps/openssl/openssl speed -elapsed -evp aes-128-gcm
./apps/openssl/openssl speed -elapsed -evp aes-256-gcm
./apps/openssl/openssl speed -elapsed -evp aes-128-cbc
./apps/openssl/openssl speed -elapsed -evp aes-256-cbc

测试二:

在不支持AES-NI扩展的移动设备上,ChaCha20-Poly1305的性能是AES-GCM的三倍左右。

图片描述

对称加密最合理的使用方法是:在支持AES-NI的设备上,优先使用AES-128-GCM加密套件;在不支持AES-NI的移动设备上,特别是ARM架构的设备上,优先使用ChaCha20-Poly1305加密套件。

Nginx实现ChaCha20-Poly1305的三种方法

OpenSSL官方版本目前不支持ChaCha20-Poly1305,所以不能使用原生的OpenSSL版本。关注OpenSSL官方的动态( https://www.openssl.org/news/changelog.html)。

在Nginx上实现ChaCha20-Poly1305主流的方法有三种:

  1. 使用OpenBSD从OpenSSL fork的分支LibreSSL;

  2. 使用Google从OpenSSL fork的分支BoringSSL;

  3. 使用CloudFlare提供的OpenSSL Patch。

主流的三种方法,都已经在服务器上部署成功并经过流量测试,各有优缺点。具体的部署方法、Nginx配置、部署过程可能会遇到的错误及解决方法,涉及的内容太多,相关内容如下:

  • Nginx编译安装BoringSSL

  • Nginx编译安装LibreSSL

  • Nginx编译安装CloudFlare提供的OpenSSL Patch

下面是我总结的这三种方法的优缺点,这个欢迎大家补充。

LibreSSL

  1. 编译安装方法最为简单;

  2. OpenBSD小组对OpenSSL的代码进行了全面清理并重构,更为轻量;

  3. 已经发布稳定版本,相比于OpenSSL团队,问题修复更及时。

BoringSSL

  1. 支持等价加密算法组功能(Equal preference cipher groups),这功能我认为很有意思,在后面博客中再介绍;

  2. 与Nginx编译友好性不足,编译容易出错,至少需要修改两处源码;

  3. 不支持OCSP Stapling功能。这一点是比较有意思的,Google工程师在博客上说OCSP Stapling存在缺陷,目前不支持,但不排除后面支持的可能性。联想到Chrome浏览器默认也不使用OCSP,可见Google对OCSP的情感是复杂的。
    https://www.imperialviolet.org/2014/04/19/revchecking.html

OpenSSL Patch

  1. 编译安装过程较为复杂;

  2. OpenSSL本身较重,存在的安全问题也多,需要频繁升级版本;

  3. 稳定性需要进一步验证。

目前野狗WildDog网站使用的是LibreSSL,来解决移动端的加速省电等新性能,如果你有疑问,或者想更多交流,或者在使用ChaCha20-Poly1305时遇到问题,都欢迎和我们联系。最后附上野狗官网(www.wilddog.com)在ssllabs上评测结果中截图。

图片描述


Hootsuite:7个重要的Twitter分析指标

$
0
0

       分析,听起来就吓人。

        现在我们要展示一些并不吓人的分析。事实上,社交网络确保分析更简单,每个人都能理解,不管是新人还是CEO。

        Twitter分析就是一个例子。不管你每天推特一次还是五十次,社交网络都会收集这些信息,以及阅读这些推特的读者的信息。而且还会以复杂但可以理解的方式呈现这些洞察。你得到的是一系列数字,快速展示你的Twitter营销成败与否,以及如何改进。

        为了使分析易于理解,我们将Twitter分析洞察细分为七个部分,这些洞察能帮助你短期内快速改善Twitter营销。

        如何访问Twitter分析

        重中之重:如何找到Twitter分析?自2014年8月分析就对所有用户开放了,你可以点击Twitter页右上角的头像,从下拉菜单中选择“分析”,或访问https://analytics.twitter.com/。你只有先访问分析页,Twitter才会开始向你推送推特数据。

        点击分析标签后会链接到一个有更多标签的首页,你需要的大部分信息可以在头三个标签中找到:首页、推特和受众。其他标签可以在你熟悉之后或是发布更复杂的Twitter广告时再使用。

        展现量

        “展现量”单独并不能提供很多信息,但是,他可以给其他指标提供更多背景信息。如果你的50条推特获得了250条转发,那相当不错。但是如果这些推特获得了50万的展现量又如何呢?说明转发获得了新的传播。展现量随着时间累积会变的更有价值。Twitter已经认识到这一点,根据时间给用户提供展现量两种不同的视图。

        首先,你可以在Analytics首页快速浏览你的展现量,就像上图。这个数字展示了过去28天你的推特展现量有多少,但是真正重要的是旁边的百分比,显示了展现量的变化,这样你就可以探究其中的秘诀了。

        在快速变化的社交媒体界,展现量变化百分数也许更重要。在推特标签下,Twitter用柱状图和时间线展示了展现量的变化,显示了每天展现量是如何变化的。图表展示了原始展现量以及推特的数量。这个图表绝妙的地方是指出哪天你的营销策略表现最好,让你找到最佳方案。图表还显示了哪类推特能够产生最多展现量。天长日久就能清晰地塑造出推特营销的最佳内容、时机和方式。

        参与率

        参与率对社交媒体营销人员来说是最重要的指标之一,参与率将若干不同指标整合为一,给你提供一个更综合的洞察,展示人们和你的互动情况。根据Twitter,参与率提供了推特内容获得的参与数量,按照展现量进行划分。参与度按互动方式划分,包括:转发、回复、追随、点赞、链接点击、网卡点击、标签点击、嵌入式媒体点击、用户名点击、资料照片点击、推特传播。

        参与率折线图展示过去一个月的进展。图表是互动式的,所以你可以悬停在某一点上收看当天的参与率。和展现量不同,折线图能向你展示参与率峰值,这样就能回溯当天的内容和推广策略,并从中获得更多收获。

        点击量

        如果非要从众多指标中选一个,那一定是点击量。点击量是一个更具体的社交媒体指标,因为它显示了用户的具体行为。

        点击量能帮助你扩展经营目标,而不仅仅是提高品牌知名度。不管你是通过登录页收集潜在客户还是推动应用下载,点击量是你实现这些目标的途径。最可贵的是能追踪你的链接,这样你就能知道什么人通过什么途径点击你的推特导航,并沿着消费者的购买路径追踪他们。

        点击量也能在Analytics的推特标签页找到,就在参与率下边。点击量以柱状图展示过去28天的情况。点击量峰值意味着你的推特内容非常有吸引力。找到这些内容,再发送一次。相同的人看到这些相同的信息的几率非常低,因此,这意味着你很可能获得一批新的潜在客户。

        受众兴趣

        社交媒体是社交工具,给营销人员接触整体受众提供机会。不像传统媒体,社交媒体用户拥有决定权。他们决定阅读什么或忽略什么。作为企业,你需要在适当的时机满足消费者的需求。Twitter提供了保障性的指标:受众的兴趣。

        受众的兴趣是分析内容之一,它展示了你的追随者正在活跃讨论的流行话题是什么。Twitter收集了这些信息并强调了你的追随者分享的大部分内容是什么。它以柱状图显示最普遍的话题,以及每个话题感兴趣的追随者的比例。

        受众的兴趣之所以重要是因为,品牌希望接触目标消费者,这些兴趣指标让你了解受众正在谈论的内容。如果你能创建适合这些主题的内容,那么,受众阅读、分享和评论这些内容的几率就会大大提升。

        兴趣洞察可以在Analytics的“受众”标签下找到,或在生活方式概述部分找到。经常检查受众的兴趣,因为随着受众的参与会不断产生新的流行话题。

关于Android的.so文件所需要知道的

$
0
0

早期的Android系统几乎只支持ARMv5的CPU架构,你知道现在它支持多少种吗?7种!

Android系统目前支持以下七种不同的CPU架构:ARMv5,ARMv7 (从2010年起),x86 (从2011年起),MIPS (从2012年起),ARMv8,MIPS64和x86_64 (从2014年起),每一种都关联着一个相应的ABI。

应用程序二进制接口(Application Binary Interface)定义了二进制文件(尤其是.so文件)如何运行在相应的系统平台上,从使用的指令集,内存对齐到可用的系统函数库。在Android系统上,每一个CPU架构对应一个ABI:armeabi,armeabi-v7a,x86,mips,arm64-v8a,mips64,x86_64。

1.为什么你需要重点关注.so文件

如果项目中使用到了NDK,它将会生成.so文件,因此显然你已经在关注它了。如果只是使用Java语言进行编码,你可能在想不需要关注.so文件了吧,因为Java是跨平台的。但事实上,即使你在项目中只是使用Java语言,很多情况下,你可能并没有意识到项目中依赖的函数库或者引擎库里面已经嵌入了.so文件,并依赖于不同的ABI。

例如,项目中使用RenderScript支持库,OpenCV,Unity,android-gif-drawable,SQLCipher等,你都已经在生成的APK文件中包含.so文件了,而你需要关注.so文件。

Android应用支持的ABI取决于APK中位于lib/ABI目录中的.so文件,其中ABI可能是上面说过的七种ABI中的一种。

Native Libs Monitor 这个应用可以帮助我们理解手机上安装的APK用到了哪些.so文件,以及.so文件来源于哪些函数库或者框架。

当然,我们也可以自己对app反编译来获取这些信息,不过相对麻烦一些。

很多设备都支持多于一种的ABI。例如ARM64和x86设备也可以同时运行armeabi-v7a和armeabi的二进制包。但最好是针对特定平台提供相应平台的二进制包,这种情况下运行时就少了一个模拟层(例如x86设备上模拟arm的虚拟层),从而得到更好的性能(归功于最近的架构更新,例如硬件fpu,更多的寄存器,更好的向量化等)。

我们可以通过Build.SUPPORTED_ABIS得到根据偏好排序的设备支持的ABI列表。但你不应该从你的应用程序中读取它,因为Android包管理器安装APK时,会自动选择APK包中为对应系统ABI预编译好的.so文件,如果在对应的lib/ABI目录中存在.so文件的话。

2.App中可能出错的地方

处理.so文件时有一条简单却并不知名的重要法则。

你应该尽可能的提供专为每个ABI优化过的.so文件,但要么全部支持,要么都不支持:你不应该混合着使用。你应该为每个ABI目录提供对应的.so文件。

当一个应用安装在设备上,只有该设备支持的CPU架构对应的.so文件会被安装。在x86设备上,libs/x86目录中如果存在.so文件的话,会被安装,如果不存在,则会选择armeabi-v7a中的.so文件,如果也不存在,则选择armeabi目录中的.so文件(因为x86设备也支持armeabi-v7a和armeabi)。

3.其他地方也可能出错

当你引入一个.so文件时,不止影响到CPU架构。我从其他开发者那里可以看到一系列常见的错误,其中最多的是"UnsatisfiedLinkError","dlopen: failed"以及其他类型的crash或者低下的性能:

使用android-21平台版本编译的.so文件运行在android-15的设备上

使用NDK时,你可能会倾向于使用最新的编译平台,但事实上这是错误的,因为NDK平台不是后向兼容的,而是前向兼容的。推荐使用app的minSdkVersion对应的编译平台。

这也意味着当你引入一个预编译好的.so文件时,你需要检查它被编译所用的平台版本。

4.混合使用不同C++运行时编译的.so文件

.so文件可以依赖于不同的C++运行时,静态编译或者动态加载。混合使用不同版本的C++运行时可能导致很多奇怪的crash,是应该避免的。作为一个经验法则,当只有一个.so文件时,静态编译C++运行时是没问题的,否则当存在多个.so文件时,应该让所有的.so文件都动态链接相同的C++运行时。

这意味着当引入一个新的预编译.so文件,而且项目中还存在其他的.so文件时,我们需要首先确认新引入的.so文件使用的C++运行时是否和已经存在的.so文件一致。

5.没有为每个支持的 CPU架构提供对应的.so文件

这一点在前文已经说到了,但你应该真的特别注意它,因为它可能发生在根本没有意识到的情况下。

例如:你的app支持armeabi-v7a和x86架构,然后使用Android Studio新增了一个函数库依赖,这个函数库包含.so文件并支持更多的CPU架构,例如新增android-gif-drawable函数库:

compile ‘pl.droidsonroids.gif:android-gif-drawable:1.1.+’

发布我们的app后,会发现它在某些设备上会发生Crash,例如Galaxy S6,最终可以发现只有64位目录下的.so文件被安装进手机。

解决方案:重新编译我们的.so文件使其支持缺失的ABIs,或者设置

ndk.abiFilters

显示指定支持的ABIs。

最后一点: 如果你是一个SDK提供者,但提供的函数库不支持所有的ABIs,那你将会搞砸你的用户,因为他们能支持的ABIs必将只能少于你提供的。

将.so文件放在错误的地方

我们往往很容易对.so文件应该放在或者生成到哪里感到困惑,下面是一个总结:

  • Android Studio工程放在jniLibs/ABI目录中(当然也可以通过在build.gradle文件中的设置jniLibs.srcDir属性自己指定)
  • Eclipse工程放在libs/ABI目录中(这也是ndk-build命令默认生成.so文件的目录)
  • AAR压缩包中位于jni/ABI目录中(.so文件会自动包含到引用AAR压缩包的APK中)
  • 最终APK文件中的lib/ABI目录中
  • 通过PackageManager安装后,在小于Android 5.0的系统中,.so文件位于app的nativeLibraryPath目录中;在大于等于Android 5.0的系统中,.so文件位于app的nativeLibraryRootDir/CPU_ARCH目录中。

只提供armeabi架构的.so文件而忽略其他ABIs的

所有的x86/x86_64/armeabi-v7a/arm64-v8a设备都支持armeabi架构的.so文件,因此似乎移除其他ABIs的.so文件是一个减少APK大小的好技巧。但事实上并不是:这不只影响到函数库的性能和兼容性。

x86设备能够很好的运行ARM类型函数库,但并不保证100%不发生crash,特别是对旧设备。64位设备(arm64-v8a, x86_64, mips64)能够运行32位的函数库,但是以32位模式运行,在64位平台上运行32位版本的ART和Android组件,将丢失专为64位优化过的性能(ART,webview,media等等)。

以减少APK包大小为由是一个错误的借口,因为你也可以选择在应用市场上传指定ABI版本的APK,生成不同ABI版本的APK可以在build.gradle中如下配置:

android {
   ... 
   splits {
	   abi {
		   enable true
		   reset()
		   include 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' //select ABIs to build APKs for
		   universalApk true //generate an additional APK that contains all the ABIs
	   }
   }
   // map for the version code
   project.ext.versionCodes = ['armeabi': 1, 'armeabi-v7a': 2, 'arm64-v8a': 3, 'mips': 5, 'mips64': 6, 'x86': 8, 'x86_64': 9]
   android.applicationVariants.all { variant ->
	   // assign different version code for each output
	   variant.outputs.each { output ->
		   output.versionCodeOverride =
				   project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI), 0) * 1000000 + android.defaultConfig.versionCode
	   }
   }
}
作者:shimiso 发表于2015/12/30 16:45:21 原文链接
阅读:0 评论:0 查看评论

Lucene实践:全文检索的基本原理

$
0
0

一、总论

根据 http://lucene.apache.org/java/docs/index.html定义:

"Apache Lucene(TM) is a high-performance, full-featured text search engine library written entirely in Java. It is a technology suitable for nearly any application that requires full-text search, especially cross-platform."

Lucene是一个高效的,基于Java的全文检索库。

所以在了解Lucene之前要费一番工夫了解一下全文检索。

那么什么叫做全文检索呢?这要从我们生活中的数据说起。

我们生活中的数据总体分为两种: 结构化数据非结构化数据

  • 结构化数据:指具有固定格式或有限长度的数据,如数据库,元数据等。
  • 非结构化数据:指不定长或无固定格式的数据,如邮件,word文档等。

当然有的地方还会提到第三种,半结构化数据,如XML,HTML等,当根据需要可按结构化数据来处理,也可抽取出纯文本按非结构化数据来处理。

非结构化数据又一种叫法叫全文数据。

 

按照数据的分类,搜索也分为两种:

  • 对结构化数据的搜索:如对数据库的搜索,用SQL语句。再如对元数据的搜索,如利用windows搜索对文件名,类型,修改时间进行搜索等。
  • 对非结构化数据的搜索:如利用windows的搜索也可以搜索文件内容,Linux下的grep命令,再如用Google和百度可以搜索大量内容数据。

对非结构化数据也即对全文数据的搜索主要有两种方法:

一种是 顺序扫描法(Serial Scanning):所谓顺序扫描,比如要找内容包含某一个字符串的文件,就是一个文档一个文档的看,对于每一个文档,从头看到尾,如果此文档包含此字符串,则此文档为我们要 找的文件,接着看下一个文件,直到扫描完所有的文件。如利用windows的搜索也可以搜索文件内容,只是相当的慢。如果你有一个80G硬盘,如果想在上 面找到一个内容包含某字符串的文件,不花他几个小时,怕是做不到。Linux下的grep命令也是这一种方式。大家可能觉得这种方法比较原始,但对于小数 据量的文件,这种方法还是最直接,最方便的。但是对于大量的文件,这种方法就很慢了。

有人可能会说,对非结构化数据顺序扫描很慢,对结构化数据的搜索却相对较快(由于结构化数据有一定的结构可以采取一定的搜索算法加快速度),那么把我们的非结构化数据想办法弄得有一定结构不就行了吗?

这种想法很天然,却构成了全文检索的基本思路,也即将非结构化数据中的一部分信息提取出来,重新组织,使其变得有一定结构,然后对此有一定结构的数据进行搜索,从而达到搜索相对较快的目的。

这部分从非结构化数据中提取出的然后重新组织的信息,我们称之 索引

这种说法比较抽象,举几个例子就很容易明白,比如字典,字典的拼音表和部首检字表就相当于字典的索引,对每一个字的解释是非结构化的,如果字典没有 音节表和部首检字表,在茫茫辞海中找一个字只能顺序扫描。然而字的某些信息可以提取出来进行结构化处理,比如读音,就比较结构化,分声母和韵母,分别只有 几种可以一一列举,于是将读音拿出来按一定的顺序排列,每一项读音都指向此字的详细解释的页数。我们搜索时按结构化的拼音搜到读音,然后按其指向的页数, 便可找到我们的非结构化数据——也即对字的解释。

 

这种先建立索引,再对索引进行搜索的过程就叫全文检索(Full-text Search)

 

下面这幅图来自《Lucene in action》,但却不仅仅描述了Lucene的检索过程,而是描述了全文检索的一般过程。

[图]全文检索的一般过程

 

全文检索大体分两个过程, 索引创建(Indexing)搜索索引(Search)

  • 索引创建:将现实世界中所有的结构化和非结构化数据提取信息,创建索引的过程。
  • 搜索索引:就是得到用户的查询请求,搜索创建的索引,然后返回结果的过程。

于是全文检索就存在三个重要问题:

1. 索引里面究竟存些什么?(Index)

2. 如何创建索引?(Indexing)

3. 如何对索引进行搜索?(Search)

下面我们顺序对每个个问题进行研究。

 

二、索引里面究竟存些什么

索引里面究竟需要存些什么呢?

首先我们来看为什么顺序扫描的速度慢:

其实是由于我们想要搜索的信息和非结构化数据中所存储的信息不一致造成的。

非结构化数据中所存储的信息是每个文件包含哪些字符串,也即已知文件,欲求字符串相对容易,也即是从文件到字符串的映射。而我们想搜索的信息是哪些 文件包含此字符串,也即已知字符串,欲求文件,也即从字符串到文件的映射。两者恰恰相反。于是如果索引总能够保存从字符串到文件的映射,则会大大提高搜索 速度。

由于从字符串到文件的映射是文件到字符串映射的反向过程,于是保存这种信息的索引称为 反向索引

反向索引的所保存的信息一般如下:

假设我的文档集合里面有100篇文档,为了方便表示,我们为文档编号从1到100,得到下面的结构

[图]字典及倒排表结构

左边保存的是一系列字符串,称为 词典

每个字符串都指向包含此字符串的文档(Document)链表,此文档链表称为 倒排表 (Posting List)。

有了索引,便使保存的信息和要搜索的信息一致,可以大大加快搜索的速度。

比如说,我们要寻找既包含字符串“lucene”又包含字符串“solr”的文档,我们只需要以下几步:

1. 取出包含字符串“lucene”的文档链表。

2. 取出包含字符串“solr”的文档链表。

3. 通过合并链表,找出既包含“lucene”又包含“solr”的文件。

[图]倒排表合并过程

看到这个地方,有人可能会说,全文检索的确加快了搜索的速度,但是多了索引的过程,两者加起来不一定比顺序扫描快多少。的确,加上索引的过程,全文检索不一定比顺序扫描快,尤其是在数据量小的时候更是如此。而对一个很大量的数据创建索引也是一个很慢的过程。

然而两者还是有区别的,顺序扫描是每次都要扫描,而创建索引的过程仅仅需要一次,以后便是一劳永逸的了,每次搜索,创建索引的过程不必经过,仅仅搜索创建好的索引就可以了。

这也是全文搜索相对于顺序扫描的优势之一:一次索引,多次使用。

 

三、如何创建索引

全文检索的索引创建过程一般有以下几步:

第一步:一些要索引的原文档(Document)。

为了方便说明索引创建过程,这里特意用两个文件为例:

文件一:Students should be allowed to go out with their friends, but not allowed to drink beer.

文件二:My friend Jerry went to school to see his students but found them drunk which is not allowed.

 

第二步:将原文档传给分词器(Tokenizer)。

分词器(Tokenizer)会做以下几件事情(此过程称为Tokenize)

1. 将文档分成一个一个单独的单词。

2. 去除标点符号。

3. 去除停词(Stop word)

所谓停词(Stop word)就是一种语言中最普通的一些单词,由于没有特别的意义,因而大多数情况下不能成为搜索的关键词,因而创建索引时,这种词会被去掉而减少索引的大小。

英语中停词(Stop word)如:“the”,“a”,“this”等。

对于每一种语言的分词组件(Tokenizer),都有一个停词(stop word)集合。

 

经过分词(Tokenizer)后得到的结果称为词元(Token)

在我们的例子中,便得到以下词元(Token):

“Students”,“allowed”,“go”,“their”,“friends”,“allowed”,“drink”,“beer”,“My”,“friend”,“Jerry”,“went”,“school”,“see”,“his”,“students”,“found”,“them”,“drunk”,“allowed”。

 

第三步:将得到的词元(Token)传给语言处理组件(Linguistic Processor)。

语言处理组件(linguistic processor)主要是对得到的词元(Token)做一些同语言相关的处理。

对于英语,语言处理组件(Linguistic Processor)一般做以下几点:

1. 变为小写(Lowercase)

2. 将单词缩减为词根形式,如“cars”到“car”等。这种操作称为:stemming

3. 将单词转变为词根形式,如“drove”到“drive”等。这种操作称为:lemmatization

 

Stemming 和 lemmatization的异同:

  • 相同之处:Stemming和lemmatization都要使词汇成为词根形式。
  • 两者的方式不同:
    • Stemming采用的是“缩减”的方式:“cars”到“car”,“driving”到“drive”。
    • Lemmatization采用的是“转变”的方式:“drove”到“drove”,“driving”到“drive”。
  • 两者的算法不同:
    • Stemming主要是采取某种固定的算法来做这种缩减,如去除“s”,去除“ing”加“e”,将“ational”变为“ate”,将“tional”变为“tion”。
    • Lemmatization主要是采用保存某种字典的方式做这种转变。比如字典中有“driving”到“drive”,“drove”到“drive”,“am, is, are”到“be”的映射,做转变时,只要查字典就可以了。
  • Stemming和lemmatization不是互斥关系,是有交集的,有的词利用这两种方式都能达到相同的转换。

 

语言处理组件(linguistic processor)的结果称为词(Term)

在我们的例子中,经过语言处理,得到的词(Term)如下:

“student”,“allow”,“go”,“their”,“friend”,“allow”,“drink”,“beer”,“my”,“friend”,“jerry”,“go”,“school”,“see”,“his”,“student”,“find”,“them”,“drink”,“allow”。

 

也正是因为有语言处理的步骤,才能使搜索drove,而drive也能被搜索出来。

 

第四步:将得到的词(Term)传给索引组件(Indexer)。

索引组件(Indexer)主要做以下几件事情:

1. 利用得到的词(Term)创建一个字典。

在我们的例子中字典如下:

TermDocument ID
student1
allow1
go1
their1
friend1
allow1
drink1
beer1
my2
friend2
jerry2
go2
school2
see2
his2
student2
find2
them2
drink2
allow2

 

2. 对字典按字母顺序进行排序。

 

TermDocument ID
allow1
allow1
allow2
beer1
drink1
drink2
find2
friend1
friend2
go1
go2
his2
jerry2
my2
school2
see2
student1
student2
their1
them2

 

3. 合并相同的词(Term)成为文档倒排(Posting List)链表。

[图]倒排表结构

 

在此表中,有几个定义:

  • Document Frequency 即文档频次,表示总共有多少文件包含此词(Term)。
  • Frequency 即词频率,表示此文件中包含了几个此词(Term)。

所以对词(Term) “allow”来讲,总共有两篇文档包含此词(Term),从而词(Term)后面的文档链表总共有两项,第一项表示包含“allow”的第一篇文档,即 1号文档,此文档中,“allow”出现了2次,第二项表示包含“allow”的第二个文档,是2号文档,此文档中,“allow”出现了1次。

到此为止,索引已经创建好了,我们可以通过它很快的找到我们想要的文档。

而且在此过程中,我们惊喜地发现,搜索“drive”,“driving”,“drove”,“driven”也能够被搜到。因为在我们的索引 中,“driving”,“drove”,“driven”都会经过语言处理而变成“drive”,在搜索时,如果您输入“driving”,输入的查询 语句同样经过我们这里的一到三步,从而变为查询“drive”,从而可以搜索到想要的文档。

 

 

三、如何对索引进行搜索?

到这里似乎我们可以宣布“我们找到想要的文档了”。

然而事情并没有结束,找到了仅仅是全文检索的一个方面。不是吗?如果仅仅只有一个或十个文档包含我们查询的字符串,我们的确找到了。然而如果结果有一千个,甚至成千上万个呢?那个又是您最想要的文件呢?

打开Google吧,比如说您想在微软找份工作,于是您输入“Microsoft job”,您却发现总共有22600000个结果返回。好大的数字呀,突然发现找不到是一个问题,找到的太多也是一个问题。在如此多的结果中,如何将最相关的放在最前面呢?

[图]Google的搜索实例

当然Google做的很不错,您一下就找到了jobs at Microsoft。想象一下,如果前几个全部是“Microsoft does a good job at software industry…”将是多么可怕的事情呀。

如何像Google一样,在成千上万的搜索结果中,找到和查询语句最相关的呢?

如何判断搜索出的文档和查询语句的相关性呢?

这要回到我们第三个问题:如何对索引进行搜索?

搜索主要分为以下几步:

第一步:用户输入查询语句。

查询语句同我们普通的语言一样,也是有一定语法的。

不同的查询语句有不同的语法,如SQL语句就有一定的语法。

查询语句的语法根据全文检索系统的实现而不同。最基本的有比如:AND, OR, NOT等。

举个例子,用户输入语句:lucene AND learned NOT hadoop。

说明用户想找一个包含lucene和learned然而不包括hadoop的文档。

第二步:对查询语句进行词法分析,语法分析,及语言处理。

由于查询语句有语法,因而也要进行语法分析,语法分析及语言处理。

1. 词法分析主要用来识别单词和关键字。

如上述例子中,经过词法分析,得到单词有lucene,learned,hadoop, 关键字有AND, NOT。

如果在词法分析中发现不合法的关键字,则会出现错误。如lucene AMD learned,其中由于AND拼错,导致AMD作为一个普通的单词参与查询。

2. 语法分析主要是根据查询语句的语法规则来形成一棵语法树。

如果发现查询语句不满足语法规则,则会报错。如lucene NOT AND learned,则会出错。

如上述例子,lucene AND learned NOT hadoop形成的语法树如下:

[图]语法树

 

3. 语言处理同索引过程中的语言处理几乎相同。

如learned变成learn等。

经过第二步,我们得到一棵经过语言处理的语法树。

[图]经过语言处理的语法树

 

第三步:搜索索引,得到符合语法树的文档。

此步骤有分几小步:

  1. 首先,在反向索引表中,分别找出包含lucene,learn,hadoop的文档链表。
  2. 其次,对包含lucene,learn的链表进行合并操作,得到既包含lucene又包含learn的文档链表。
  3. 然后,将此链表与hadoop的文档链表进行差操作,去除包含hadoop的文档,从而得到既包含lucene又包含learn而且不包含hadoop的文档链表。
  4. 此文档链表就是我们要找的文档。

第四步:根据得到的文档和查询语句的相关性,对结果进行排序。

虽然在上一步,我们得到了想要的文档,然而对于查询结果应该按照与查询语句的相关性进行排序,越相关者越靠前。

如何计算文档和查询语句的相关性呢?

不如我们把查询语句看作一片短小的文档,对文档与文档之间的相关性(relevance)进行打分(scoring),分数高的相关性好,就应该排在前面。

那么又怎么对文档之间的关系进行打分呢? 这可不是一件容易的事情!

下面看一下 如何判断文档之间的关系

首先,一个文档有很多词(Term)组成,如search, lucene, full-text, this, a, what等。

其次对于文档之间的关系,不同的Term重要性不同,比如对于本篇文档,search, Lucene, full-text就相对重要一些,this, a , what可能相对不重要一些。所以如果两篇文档都包含search, Lucene,fulltext,这两篇文档的相关性好一些,然而就算一篇文档包含this, a, what,另一篇文档不包含this, a, what,也不能影响两篇文档的相关性。

因而判断文档之间的关系,首先找出哪些词(Term)对文档之间的关系最重要,如search, Lucene, fulltext。然后判断这些词(Term)之间的关系。

 

找出词(Term)对文档的重要性的过程称为计算词的权重(Term weight)的过程。

计算词的权重(term weight)有两个参数,第一个是词(Term),第二个是文档(Document)。

词的权重(Term weight)表示此词(Term)在此文档中的重要程度,越重要的词(Term)有越大的权重(Term weight),因而在计算文档之间的相关性中将发挥更大的作用。

判断词(Term)之间的关系从而得到文档相关性的过程应用一种叫做向量空间模型的算法(Vector Space Model)

 

下面仔细分析一下这两个过程:

1. 计算权重(Term weight)的过程。

影响一个词(Term)在一篇文档中的重要性主要有两个因素:

  • Term Frequency (tf):即此Term在此文档中出现了多少次。tf 越大说明越重要。
  • Document Frequency (df):即有多少文档包含次Term。df 越大说明越不重要。

容易理解吗?词(Term)在文档中出现的次数越多,说明此词(Term)对该文档越重要,如“搜索”这个词,在本文档中出现的次数很多,说明本文 档主要就是讲这方面的事的。然而在一篇英语文档中,this出现的次数更多,就说明越重要吗?不是的,这是由第二个因素进行调整,第二个因素说明,有越多 的文档包含此词(Term), 说明此词(Term)太普通,不足以区分这些文档,因而重要性越低。

这也如我们程序员所学的技术,对于程序员本身来说,这项技术掌握越深越好(掌握越深说明花时间看的越多,tf越大),找工作时越有竞争力。然而对于所有程序员来说,这项技术懂得的人越少越好(懂得的人少df小),找工作越有竞争力。人的价值在于不可替代性就是这个道理。

道理明白了,我们来看看公式:

[图]权重计算公式

[图]权重计算公式变量

 

这仅仅只term weight计算公式的简单典型实现。实现全文检索系统的人会有自己的实现,Lucene就与此稍有不同。

2. 判断Term之间的关系从而得到文档相关性的过程,也即向量空间模型的算法(VSM)。

我们把文档看作一系列词(Term),每一个词(Term)都有一个权重(Term weight),不同的词(Term)根据自己在文档中的权重来影响文档相关性的打分计算。

于是我们把所有此文档中词(term)的权重(term weight) 看作一个向量。

Document = {term1, term2, …… ,term N}

Document Vector = {weight1, weight2, …… ,weight N}

同样我们把查询语句看作一个简单的文档,也用向量来表示。

Query = {term1, term 2, …… , term N}

Query Vector = {weight1, weight2, …… , weight N}

我们把所有搜索出的文档向量及查询向量放到一个N维空间中,每个词(term)是一维。

如图:

[图]向量空间模型

 

我们认为两个向量之间的夹角越小,相关性越大。

所以我们计算夹角的余弦值作为相关性的打分,夹角越小,余弦值越大,打分越高,相关性越大。

有人可能会问,查询语句一般是很短的,包含的词(Term)是很少的,因而查询向量的维数很小,而文档很长,包含词(Term)很多,文档向量维数很大。你的图中两者维数怎么都是N呢?

在这里,既然要放到相同的向量空间,自然维数是相同的,不同时,取二者的并集,如果不含某个词(Term)时,则权重(Term Weight)为0。

 

相关性打分公式如下:

[图]相关性打分的公式

 

举个例子,查询语句有11个Term,共有三篇文档搜索出来。其中各自的权重(Term weight),如下表格。

 

t1

t2

t3

t4

t5

t6

t7

t8

t9

t10

t11

D1

0

0

.477

0

.477

.176

0

0

0

.176

0

D2

0

.176

0

.477

0

0

0

0

.954

0

.176

D3

0

.176

0

0

0

.176

0

0

0

.176

.176

Q

0

0

0

0

0

.176

0

0

.477

0

.176

于是计算,三篇文档同查询语句的相关性打分分别为:

[图]文档一的打分计算

[图]文档二的打分计算

[图]文档三的打分计算

 

于是文档二相关性最高,先返回,其次是文档一,最后是文档三。

到此为止,我们可以找到我们最想要的文档了。

说了这么多,其实还没有进入到Lucene,而仅仅是信息检索技术(Information retrieval)中的基本理论,然而当我们看过Lucene后我们会发现,Lucene是对这种基本理论的一种基本的的实践。所以在以后分析 Lucene的文章中,会常常看到以上理论在Lucene中的应用。

在进入Lucene之前,对上述索引创建和搜索过程所一个总结,如图:

此图参照 http://www.lucene.com.cn/about.htm中文章《开放源代码的全文检索引擎Lucene》

[图]索引创建和搜索过程

 

1. 索引过程:

1) 有一系列被索引文件

2) 被索引文件经过语法分析和语言处理形成一系列词(Term)

3) 经过索引创建形成词典和反向索引表。

4) 通过索引存储将索引写入硬盘。

2. 搜索过程:

a) 用户输入查询语句。

b) 对查询语句经过语法分析和语言分析得到一系列词(Term)

c) 通过语法分析得到一个查询树。

d) 通过索引存储将索引读入到内存。

e) 利用查询树搜索索引,从而得到每个词(Term)的文档链表,对文档链表进行交,差,并得到结果文档。

f) 将搜索到的结果文档对查询的相关性进行排序。

g) 返回查询结果给用户。



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


ITeye推荐



乌云曝三大运营商流量计费系统漏洞:客户可免费多用流量

$
0
0

【TechWeb报道】12月30日消息,乌云平台一则公告称,发现移动、联通、电信三大运营商流量计费系统漏洞,客户可以利用该漏洞免费使用远远超出其套餐的流量。

乌云曝移动、联通、电信流量计费系统漏洞

乌云曝移动、联通、电信流量计费系统漏洞

乌云公告显示,漏洞细节已通知厂商,正等待厂商处理。

乌云对漏洞详情的描述:

披露状态:

2015-12-29:细节已通知厂商并且等待厂商处理中

简要描述:

三大运营商流量计费检测系统漏洞,有些客户会对此漏洞加以利用从而使用远远超出其套餐的流量,倘若漏洞扩大,会使运营商损失过大。

成因:运营商为了给客户提供方便,提供了优惠政策,如:接收彩信、登陆掌厅免除流量费以及免收取流量费的其他业务。

运营商的计费系统为了区分用户使用的是免流量业务还是正常访问互联网会把这些免流服务的网址加入到白名单,当计费系统检测到用户访问的是白名单中的网址或接收彩信时就不会进行扣费。

问题出在检测上,当用户访问互联网时,向服务器发送一条http请求头,请求头中包含了访问的网址、UA、网络协议、主机(host)、Cookie、来源地址、文件类型等信息。计费系统通过检测请求头来分辨用户访问的是不是白名单中的网址或者是接收彩信。但是计费系统检测的是用户发来的请求信息,这条信息是来自于用户的,通过自定义该信息可以达到欺骗计费检测达到免流量上网的目的。

漏洞hash:cad8aa6cd230452be0d11dd6ab9a023c

蚕豆网微信

快速建筑设计是如何发展到现在的?

$
0
0

建筑教育史抑或建筑考试史,也差不多算是建筑史下的显学了,虽然细想来也没大必要,—— 不靠这行混饭的话。因此,专门的建筑考试史之快题史我不曾钻研过,但闲读时曾有相关寓目,可以凑出一个大体的画面看:

1. 「快速建筑设计」作为一项考察设计能力的方法,由来已久,「考研快题」只是它在中国的一个变体。例证至少可见杨廷宝、冯纪忠回忆。两人相隔一代,一个在仍尚布札学派(Beaux Arts;法语,即 Fine Arts,美术,视建筑为美术范畴;建筑专业开在美院中)的美国,宾大;一个在已然吸收现代主义建筑理念的欧陆,维也纳工大。前者会有快速设计,给定几天时间,在图房里,每人交出一张以一座假想的未完工的大教堂为基础的全套图纸,包括平面剖面及立面渲染;后者细节一时难以查考,但也分明是有的。这是随手搜到的一例:



2. 因此,大可不必将「考研快题」视作我国建筑教育中的独创;许多年前,我自己也曾问老师,我们大一就练仿宋字,即「工程字体」,那么外国人练什么?—— 当然是练字母了。这是梁思成测稿,可见「字体」汉化之辙:


3. 题主问「国外有没有类似的考查机制?」问得好。试答如下:
国内注册建筑师资格考试,是90年代起,参照美国等同行制度拟定的,其中自然会考建筑设计,自然就有快题。而研究生考试呢,自然沿用。但国内之所以把「考研快题」弄得那么重要,正是这个缘故,—— 从来都分不清面向行业的职业考试,和面向专业的潜力测试。你搜搜这建筑师考试出题的大佬,跟建筑师考试培训班的金牌,跟《建筑学考研快题100例》的主编是几个人,就了然了。所以,尽管人会同意,注册建筑师尽可以用快题刷去不合格的脑洞携带者,免得放出去祸害人类;可读研呢?爱读的读,考一考,刷出脑洞来作为录取的参考得了,何必弄个快题成生死关,考题整得像集体操一样严,又或像杂技一样难?至少国外建筑学的硕士教育,鲜闻「考研快题」这玩意。

来源:知乎 www.zhihu.com
作者: 知乎用户(登录查看详情)

【知乎日报】千万用户的选择,做朋友圈里的新鲜事分享大牛。 点击下载

此问题还有 3 个回答,查看全部。
延伸阅读:
怎样快速学习rhino和grasshopper?
时至今日,建筑老八校的建筑学专业发展如何?

最新诈骗短信解析及预防

$
0
0
今天, @公安部打四黑除四害发如下微博:
【警惕最新诈骗短信!】据网友,短信中HK代表的是换卡、后面的数字代表的是新的sim卡卡号!新卡在骗子手里,用户的卡就不能用了。这样一来,骗子可能轻松转走你绑定的银行卡、支付宝或者微信账户资金。扩散提醒! 诈骗原理:
①群发短信诱导你发换卡申请到10086(申请中已包含骗子手里新SIM卡的临时号码),其中HK是换卡提示符,最后11位为骗子所获得新SIM卡的临时号码,其他内容任意。如果你按其提示将相应内容发送给10086,意味着你发起了远程换SIM卡申请。
②10086收到后,会给你发一条短信,问你是否确认现在所用的手机号换SIM卡,如你收到10086所发换卡确认短信并回复了Y,那么你就把骗子的卡激活了,而你手里的卡则作废了。
③此时骗子在手机里的卡会收到10086发来的换卡成功短信,这时骗子可以用你的手机号打电话发短信,更重要的是,如果你的手机号绑定了网银或微信支付、支付宝之类的,还可能带来资金损失。

分析:
  • 此案例为利用用户不熟悉中国移动远程换卡功能而实施的骗号诈骗行为。
  • 短信不一定是12520开头(此为飞信短信开通),也可能伪装成任何号码,包括10086,110。

预防要点:
①运营商不会远程短信要求你回复长短信(除充值密码),也就是说,如果你收到运营商短信发来的回复长短信的提示,一般都为假的,应拨打官方客服(10086)确认。短信中的内容本就为引起恐慌,越是这样,你越应该咨询客服。错误计费不仅会返还,还可能获得加倍补偿。
②回复运营商客服短信前要看清问题,如此短信,看清提示,不回复“Y”,骗子的换卡伎俩就不会成功。
③运营商远程换卡流程应更严谨一些,例如,如果能够通过基站定位锁定换卡地点,可避免大部分此类诈骗。

 

Java图像处理库 Sanselan

$
0
0

Sanselan 是一个纯 Java 的图形库,可以读写各种格式的图像文件,包括快速解析图片信息例如大小/颜色/icc以及元数据等。尽管因为是Java开发的,在处理速度上会稍微慢一 些,但具备良好的可移植性。虽然尚未发布1.0 版本,但是已经有多个项目在使用 Sanselan 来处理图像文件。

该项目目前还是 Apache 组织的一个孵化项目。

JavaDoc: http://www.apache.org/dist/incubator/sanselan/javadoc/

示例代码:

File file = someFile;
BufferedImage image_3 = Sanselan.getBufferedImage(file);
InputStream is = someInputStream;
BufferedImage image_4 = Sanselan.getBufferedImage(is);

// Write an image.
BufferedImage image = someImage;
File dst = someFile;
ImageFormat format = ImageFormat.IMAGE_FORMAT_PNG;
Map optional_params = new Hashtable();
Sanselan.writeImage(image, dst, format, optional_params);

OutputStream os = someOutputStream;
Sanselan.writeImage(image, os, format, optional_params);

// get the image's embedded ICC Profile, if it has one.
byte icc_profile_bytes[] = Sanselan.getICCProfileBytes(imageBytes);

ICC_Profile icc_profile = Sanselan.getICCProfile(imageBytes);

// get the image's width and height.
Dimension d = Sanselan.getImageSize(imageBytes);

// get all of the image's info (ie. bits per pixel, size, transparency, etc.)
ImageInfo image_info = Sanselan.getImageInfo(imageBytes);

if (image_info.getColorType() == ImageInfo.COLOR_TYPE_GRAYSCALE)
System.out.println("Grayscale image.");
if (image_info.getHeight() > 1000)
System.out.println("Large image.");

// try to guess the image's format.
ImageFormat image_format = Sanselan.guessFormat(imageBytes);
image_format.equals(ImageFormat.IMAGE_FORMAT_PNG);

// get all metadata stored in EXIF format (ie. from JPEG or TIFF).
// org.w3c.dom.Node node = Sanselan.getMetadataObsolete(imageBytes);
IImageMetadata metdata = Sanselan.getMetadata(imageBytes);

// print a dump of information about an image to stdout.
Sanselan.dumpImageFile(imageBytes);

// get a summary of format errors.
FormatCompliance format_compliance = Sanselan
.getFormatCompliance(imageBytes);

 

http://www.oschina.net/p/sanselan/similar_projects?lang=22&sort=view



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


ITeye推荐




Google不想与甲骨文争了,要放弃Java APIs

$
0
0

Google不想与甲骨文争了,要放弃Java APIs

与Android崛起相伴的其实还有战争,而其中最重要且最有争议性的,恐怕就是甲骨文和Google的官司了。

自2010年起,两家公司关于Android系统的一部分是否侵犯了甲骨文的版权和专利,一起争论不休,因为系统中使用了甲骨文拥有的Java。整个官司既持久,又充满戏剧性。

但Google似乎有些乏了,于是决定从下一代的Android N(应该会在2016年发布)开始,系统将不再使用Java APIs。新Android将使用OpenJDK,这是Java SE的一个开源版本,诞生于2007年。有趣的是,Java SE也属于甲骨文,不过是开源的,而且开发的当时甲骨文还没收购(发生在2010年)Sun Microsystems,变身Java的实际拥有者。

Google已经向外媒VB确认了这一消息,而起因是有开发者发现 Android的开源进程中有一些“神秘”的描述。Google对此的回应是:

Android是一个开源平台,是开源社区合作的结晶。在下一版的Android中,我们计划将Java语言库换为以OpenJDK为基础,开发一个通用代码库,方便开发者开发应用和服务。Google与OpenJDK有长期的合作,未来也会为它做更多贡献。

虽然Google还说,这种改变是因为想使用第8版Java的功能,但毫无疑问,不想再与甲骨文纠缠也是重要的原因。

其实官司中双方的争论点倒不是Google是否在Android中使用了Java APIs,它对此也没有否定,因为这样能让数百万的开发者为自己开发应用。Google的论点是,APIs不能有版权,它本来就是用来让应用间相互交流,而很多公司也会让开发者自由使用。甲骨文对此的态度当然是我不听我不听我不听。

按现在的发展来看,甲骨文在官司中还是占优势,Google或许要赔60亿美元(但没得到法院认可),最可能的情况是不能再用有版权的APIs。

至于整个事件的发展是怎么样的,又与我们有什么关系, 可以阅读雷锋网的这篇文章

来自蘑菇街的开源IM:TeamTalk

$
0
0

TeamTalk 是蘑菇街开源的一款企业办公即时通信软件,最初是为自己内部沟通而做的 IM 工具。

项目框架

麻雀虽小五脏俱全,本项目涉及到多个平台、多种语言,简单关系如下图:

teamtalk-1

服务端:

  • CppServer:TTCppServer工程,包括IM消息服务器、http服务器、文件传输服务器、文件存储服务器、登陆服务器
  • Java DB Proxy:TTJavaServer工程,承载着后台消息存储、redis等接口
  • PHP server:TTPhpServer工程,teamtalk后台配置页面

客户端:

  • mac:TTMacClient工程,mac客户端工程
  • iOS:TTIOSClient工程,IOS客户端工程
  • Android:TTAndroidClient工程,android客户端工程�
  • Windows:TTWinClient工程,windows客户端工程

语言:c++、objective-c、java、php

系统环境:Linux、Windows,Mac, iOS, Android

作为整套系统的组成部分之一,TTServer为TeamTalk 客户端提供用户登录,消息转发及存储等基础服务。TTServer主要包含了以下几种服务器:

  • LoginServer (C++): 登录服务器,分配一个负载小的MsgServer给客户端使用
  • MsgServer (C++): 消息服务器,提供客户端大部分信令处理功能,包括私人聊天、群组聊天等
  • RouteServer (C++): 路由服务器,为登录在不同MsgServer的用户提供消息转发功能
  • FileServer (C++): 文件服务器,提供客户端之间得文件传输服务,支持在线以及离线文件传输
  • MsfsServer (C++): 图片存储服务器,提供头像,图片传输中的图片存储服务
  • DBProxy (JAVA): 数据库代理服务器,提供mysql以及redis的访问服务,屏蔽其他服务器与mysql与redis的直接交互

当前支持的功能点:

  • 私人聊天
  • 群组聊天
  • 文件传输
  • 多点登录
  • 组织架构设置.

系统结构图

teamtalk-2

  • login_server:均衡负载服务器,用来通知客户端连接到负载最小的msg_server (1台)。
  • msg_server:客户端连接服务器(N台)。客户端通过msg_server登陆,保持长连接。
  • route_server:消息中转服务器(1台)。
  • DBProxy:数据库服务,操作数据库(N台)。

消息收发流程:

  1. msg_server启动时,msg_server主动建立到login_server和route_server的长连接。
  2. 客户端登陆时,首先通过login_server 获取负载最小的msg_server。连接到msg_server。登陆成功后,msg_server发消息给route_server,route_server记录用户的msg_server。与此同时,msg_server发送消息给login_server,login_server收到后,修改对应msg_server的负载值。
  3. 客户端消息发送到msg_server。msg_server判断接收者是否在本地,是的话,直接转发给目标客户端。否的话,转发给route_server。
  4. route_server接收到msg_server的消息后,获取to_id所在的msg_server,将消息转发给msg_server。msg_server再将消息转发给目标接收者。

数据库操作:

  • 消息记录,获取用户信息等需要操作数据库的,由msg_server发送到db_server。db_server操作完后,发送给msg_server。

参考链接: http://www.bluefoxah.org/

TeamTalk 之 Mac 客户端架构分析

项目结构

在软件架构中,一个项目的目录结构至关重要,它决定了整个项目的架构风格。通过一个规范的项目结构,我们应该能够很清楚的定位相应逻辑存放位置,以及能够没有歧义的在指定目录中进行新代码的撰写。项目结构便是项目的骨架,如果存在畸形和缺陷,项目的整体面貌就会受到很大影响。我们来看看TeamTalk的项目根结构:

teamtalk-3

从整个项目结构图中,我们大致能猜出一些目录中存放的是什么,以下是这些目录的主要意图:

  • html:存放着一些HTML相关文件,用于项目中一些用户界面与HTML进行Hybrid。
  • customView:一些公共的自定义视图,同样与用户界面相关。
  • Services:封装了两个服务,应用更新检测,和用户搜索。
  • HelpLib:一些公共的帮助库。
  • Category:顾名思义,这里存放的都是现有类的Category。
  • Modules:按照功能和业务进行划分的一系列模块。
  • DDLogic:这里面主要存放着一个模块化框架。
  • teamtalk:这里面是和TeamTalk应用级别相关的东西。
  • views:视图,原本应该是存放应用所有视图的地方。
  • Libraries:第三方库。
  • utilities:一些通用的帮助类和组件。
  • 思考与分析

首先,从总体来说,这样的目录结构划分,似乎可以涵盖到整个项目开发的所有场景,但它存在以下几个很明显的问题:

  • 命名不够规范,对于有态度的人来说,看到这样的目录结构,可能首先就会将它们的大小写进行统一,然后单复数进行统一。虽然这可能并不会对最终应用有任何的提升,但我说过,态度决定一切,既然开源了,这样的规范更应该值得注重。
  • 除了大小写之外,DDLogic也是让人非常费解的命名,Logic是什么?它是逻辑?那么似乎整个应用的源码都可以放置到这里了。这里的问题,就跟我们建立了一个h和Common.h一样,包罗万象,但这不应该是我们遵从的。命令体现的是抽象能力,它应该是明确的,模棱两可会导致它在项目的迭代中要么被淘汰,要么膨胀到让人无法忍受。
  • 类别划分有歧义,HelpLib和Utilities,似乎根本就无法去辨别它们之间的区别,这两者应该进行合并。并且Helper类本身就不是很好的设计方式,可以通过Category来尽量减少Helper,无法通过Category扩展的,应该按照类的实际行为进行更好的命名和划分。
  • 含有退化的类别,所谓退化的类别,就是项目初期原本的设定,在后续的迭代重构中渐渐失去作用或者演化为另外的形式。这里的Views和Services是很好的例子,这两个目录存放在根目录下非常鸡肋,既然已经按模块化进行划分,那么Services可以拆分到相应的模块里;Views也是类似,应该拆分到相应模块和CustomView中。
  • 含有臃肿的类别,这一点也是显而易见的,之所以臃肿,是因为里面放了不应该放的东西。这里主要体现在Modules这个目录,我们应该把不属于模块实现的东西提取出来,包括数据存储、系统配置、一些通用组件。这些应该安置到根目录相应分类中,而明显层次化的东西,应该提取到单独库或目录中,比如网络API相关的东西。
  • 没有意义的单独归类,这里体现在Html这个目录,应该和Supporting Files目录中的资源进行合并,统一归类为Resources,然后再按照资源的类别进行细分。

项目结构的划分应该做到有迹可循,也就是说是按照一定的规则进行划分。这里主要的划分依据是逻辑模块化,这样的方式我还是比较赞同的,虽然有很多细节没有处理好,但主线还是很好的。

网络数据处理

在任何需要联网的应用中,网络数据处理都是非常重要的,这点在IM中更是毋庸置疑。IM与很多其它应用相比,更具挑战,它需要处理很多即时消息,并且很多时候需要自己去构建一套通讯机制。

TeamTalk中,主要使用HTTP和TCP进行通讯,我们知道HTTP是基于TCP的更高层协议,而这里的TCP通讯是指用TCP协议发送自定义格式的报文。TeamTalk在HTTP通讯中使用的是RESTful API,并使用JSON格式与服务器进行交换数据;而在TCP这里,主要是通过ProtocolBuffer序列化协议,加上自定义的包头与服务器进行通信。

HTTP数据处理

HTTP的数据处理,在TeamTalk中显得非常简单,并没有做过多的设计。主要是使用AFNetworking封装了一个HTTP模块:

DDHttpModule.h

typedef void(^SuccessBlock)(NSDictionary *result);
typedef void(^FailureBlock)(StatusEntity* error);

@interface DDHttpModule : DDModule
 
-(void)httpPostWithUri:(NSString *)uri params:(NSDictionary *)params success:(SuccessBlock)success failure:(FailureBlock)failure;
-(void)httpGetWithUri:(NSString *)uri params:(NSDictionary *)params success:(SuccessBlock)success failure:(FailureBlock)failure;

@end

extern DDHttpModule* getDDHttpModule();

这样一个模块会被其它模块进行使用,直接传递uri请求服务器,并解析响应,以下是一个使用场景:

DDHttpServer.m

- (void)loginWithUserName:(NSString*)userName
                 password:(NSString*)password
                  success:(void(^)(id respone))success
                  failure:(void(^)(id error))failure
{
    DDHttpModule* module = getDDHttpModule();
    NSMutableDictionary* dictParams = [NSMutableDictionary dictionary];
    ...(省略参数赋值)
    
    [[NSURLCache sharedURLCache] removeAllCachedResponses];
    [module httpPostWithUri:@"user/zlogin/" params:dictParams
                    success:^(NSDictionary *result) { success(result); }
                    failure:^(StatusEntity *error) { failure(error.msg); }
    ];
}

即便是这样的一个封装,在后续的迭代中似乎也慢慢失去了作用,目前大部分所使用到HTTP的代码里,都是直接使用AFNetworking,那么这样的一个封装已经没有存在的必要了。

TCP数据处理

在TeamTalk里,针对TCP的数据处理略显复杂,因为没有类似AFNetworking这样的类库,所以需要自己封装一套处理机制。大致类图如下:

teamtalk-4

通过这样的一个类图,我们大致可以推断出设计者的抽象思维,他把所有网络操作抽象为API。基于这样思路,这里有三个最核心的类:

  • DDSuperAPI:这个类是对所有Request/Response这种模式网络的请求进行的抽象,所有遵循这种模式的API都需要继承这个类。
  • DDUnrequestSuperAPI:这个和DDSuperAPI相对应,也就是所有非Request/Response模式的网络请求,基本上都是服务端推送过来的消息。
  • DDAPISchedule:API调度器(应该改名为DDAPIScheduler),顾名思义,是用来调度所有注册进来的API,这个类主要做了以下几件事情:
    • 通过DDTcpClientManager接收和发送数据包。
    • 通过seqNo和数据包标识符(ServiceID和CommandID,这里源码中CommandID拼写有误哦),映射Request和Response,并将服务端的响应派发到正确的API中。
    • 管理响应超时,确保每一个Request都会有应答。

基于这样一个设计,我们来看一个基本的登录操作序列图:

teamtalk-5

所有基于请求响应模式的操作,都是与上图类似,而服务端推送过来的消息,也是类似,只是没有了请求的过程。通过我的分析,大家觉得这样的设计怎么样?首先从扩展性的角度考虑,每一个API都相对独立,增加新的API非常容易,所以扩展性还是很不错的;其次从健壮性的角度考虑,每一个API都由调度器管理,调度器可以对API进行一些容错处理,API本身也可以做一些容错处理,这一点也还是可以的;最后从使用者的角度考虑,API对外暴露的接口非常简单,并且对于异步操作使用Block返回,对于组织代码还是非常有用的,所以使用者也觉得良好。

那么,这是一个完美的设计了么?我说过,没有完美的设计,只有符合特定场景的设计。针对这个设计,撇开它一些命名问题,以下是我觉得它不足的地方:

  • 子类膨胀,恰恰是为了更好的扩展性,而带来了这样的问题,由于一个API最多只能处理两个协议包(Request,Response),所以协议众多时,导致API子类泛滥,而所做的基本都是相似事情。TeamTalk这种形式的封装,本质上是采用了Command模式,这个模式在面向对象的设计中本身就充满争议,因为它是封装行为(面向过程的设计),但也有它适用的场景,比如事务回滚、行为组合、并发执行等,但这里似乎都用不到。所以,我觉得TeamTalk这样的设计并不是特别合适,或许使用管道设计会更好点。
  • 调度器职责不单一,为什么说它的职责不单一呢?因为引起它的变化点不止一处,很显然的,发送数据不应该纳入调度器的职责中。另外DDSuperAPI和DDUnrequestSuperAPI全部由这一个调度器来调度,也是有点别扭的,前者响应分发完后必须要从列表中移除,后者又绝对不能被移除,这样鲜明的差异性在设计中是不应该存在的,因为它会导致一些使用上的问题。

总体来说,这样的一个框架还是不错的,因为它的抽象层次不高,很容易去理解和维护,并且完成了大家的预期,这样或许就已经足够了。

本地持久化

本地持久化是个可以有很多设计的地方,但在APP中,进行设计的情况并不是很多,因为APP本身对于持久化的要求没有MIS高,一般只是做些离线缓存,而在IM中,它还负责存储历史消息等结构化数据。TeamTalk对于持久化这块,也没有做什么设计,只是依托于FMDB封装了一个MTDatabaseUtil,这是一个类似于Helper的存在,里面聚集了所有APP会用到的存储方法。毋庸置疑,这样的封装会导致类比较庞大,好在TeamTalk中存储方法并不多,并且使用了Catagory对方法进行了分类,所以总体感觉也还是可以的。另外,从残存的目录结构中可以看出,TeamTalk原本可能是想采用CoreData,但最终放弃了,或许是觉得CoreData整体不够轻量级吧。

MTDatabaseUtil和API一样,都只能算是基础设施(Infrastructure),给高层模块提供支持,高层模块会使用这些基础设施根据业务逻辑进行封装,可以看一个具的代码片段:

MTGroupModule.m

- (void)getOriginEntityWithOriginIDsFromRemoteCompletion:(NSArray*)originIDs completion:(DDGetOriginsInfoCompletion)completion{
    ...(省略)
    
    DDGroupInfoAPI *api = [[DDGroupInfoAPI alloc] init];
    [api requestWithObject:param Completion:^(id response, NSError *error) {
        if (!error) {
            NSMutableArray* groupInfos = [response objectForKey:@"groupList"];
            [self addMaintainOriginEntities:groupInfos];
            [[MTDatabaseUtil instance] insertGroups:groupInfos];
            completion(groupInfos,error);
        }else{
            DDLog(@"erro:%@",[error domain]);
        }
    }];
}

理想中,只会在业务模块里依赖持久化操作库,但从TeamTalk总体使用情况中看,并不是这么理想,很多Controller里面直接对MTDatabaseUtil进行了操作,这样就削弱了模块化封装的意义。显然,Controller的职责不应该牵扯到数据持久化,这些都应该放置在相应的业务模块里,统一对外屏蔽这些实现细节。

模块化设计

模块化设计是更高层次的抽象和复用,也是业务不断发展后必然的设计趋势。在进入目前公司的第二周例会上,我便分享了一个亲手设计的模块化框架,这个框架和TeamTalk模块化框架有很多类似之处,好坏暂不做对比,我们先看看TeamTalk中的一个模块化架构。在TeamTalk的DDLogic目录下,隐藏着一个模块化的设计,这也是整个项目中模块设计的基础构件,以下是这个设计的核心类图:

teamtalk-6

  • DDModule:最基础的模块抽象,所有模块的基类,包含自己的生命周期方法,并提供一些模块共有方法。
  • DDTcpModule:拥有TCP通讯能力的模块,监听网络数据,子类化模块可以就此进行业务封装。
  • DDModuleDataManager:按照模块的粒度进行持久化操作,负责持久化和反持久化所有模块。
  • DDModuleManager:管理所有模块,负责调用模块生命周期方法,并对外提供模块获取方法。

整个设计还是很简单明了的,但不知是TeamTalk设计者更换了,还是原设计者变心了,导致这个模块化设计没有起到它预期的作用。具体原因就不细究了,但这样的设计还是值得去推演的,就目前这样的设计而言,也还是缺少了一些东西:

  • DDModule应该通过DDModuleManager注入一些基础设施,比如数据库访问组件、缓存组件、消息组件等。
  • DDModule应该有获取到其它模块的能力,这里面不应该反依赖与DDModuleManager,可以抽象一个ModuleProvider注入到DDModule中。
  • 可通过Objective-C对象的load方法,在模块实现类中直接注册模块到模块管理器里,这样会更加内聚。

虽然我觉得有点缺失,但还是很欣慰的看到了这样的模块化设计,又让我想起一些往事,这种心情,就像遇见了一个和初恋很像的人。

UI相关设计

整个UI设计也没什么特别之处,主要还是采用了xib进行布局,然后连线到相应的Controller中,这里主要的WindowController是DDMainWindowController,它是在登录窗口消失后出现的,也就是DDLoginWindowController所控制的窗口消失后。

值得一提的是,这里将所有的UI都放置到了相应的业务模块中,这也是我比较推崇的做法。一个模块本就应该能够自成一系,它应该有自己的Model,有自己的View,也有自己的Controller,还可以有自己的Service等。这样设计下的模块才会显得更加内聚,其实设计就是这么简单,小到类,大到组件都应该遵循内聚的原则。

其它组件

TeamTalk中还使用了一些个第三方组件,具体罗列如下:

  • CrashReporter:用于崩溃异常收集。
  • Sparkle:用于软件自动更新。
  • Adium:OSX下的一个开源的IM,TeamTalk中使用了其中的一些框架和类。

总结

TeamTalk作为一个敢于开源出来的IM,还是非常值得赞扬的,国内的技术氛围一直提高不起来,大家似乎都在闭门造车。如果多一些像蘑菇街这样的开源行为,应该能够更好的促进圈子里的技术生态。虽然,这篇博文里提出了很多TeamTalk Mac客户端架构的不足之处,但,设计本身就是如此,根本没有最好的设计,而,每个设计者的眼光也不相同,或许我说得都不正确也不见得。

所以,只要有颗敢于尝试设计的心,开放的态度,一切问题都不是问题。

原文地址: http://blog.makeex.com/2015/05/30/the-architecture-of-teamtalk-mac-client/

TT流程随笔

细节:

  • 如果本地可以自动登录, 先实现本地登录,发送事件通知,再请求登录服务器
  • 如果本地不可以登录(第一次或退出后),直接请求登录服务器
  • 登录服务器返回消息服务器ip port / 文件服务器
  • 链接消息服务器(socketThread 通过netty)
  • 链接成功或失败都发送事件通知 (可能是在loginactivity 处理,也可能在chatfragment处理,你懂滴)
  • 链接失败弹出界面提示
  • 链接成功 请求登录消息服务器(发送用户名 密码 etc)并且同时开启 回掉监听队列计时器(这个稍后再细看吧~)
  • 登录消息服务器成功或失败都通过回掉 (回掉函数存储在packetlistner 中)处理
  • 登录消息服务器失败 发送总线事件,也可能在两个位置处理(loginactvity/chatfragment ,你懂得~)
  • 消息服务器登录成功,并解析返回的登录信息,发送登录成功的事件总线,事件的订阅者分为service 和 activity ,activity 中的事件负责ui的更新处理,service中事件处理,消息的进一步获取 ,与服务器打交道
  • 判断登录的类型(普通登录和本地登录成功后的消息服务器登录)
  • service 收到登录成功(此指在线登录成功,本地登录成功也是一个道理,发送事件更新界面ui和在service中事件触发进一步的消息获取(获取本地库))的事件通知(按登录类型有所不同 ,大体一致)后,做如下工作:
    • 保存本次的登录标示到xml
    • 初始化数据库(创建或获取当前用户所在数据库统一操作接口单例)
    • 请求联系列表
    • 请求群组列表
    • 请求最近会话列表
    • 请求未读消息列表(只是在线登录状态)
    • 重连管理类的相关设置(广播的注册等)

接下来就是对服务端发送消息过来的分析

  • 服务端发送消息过来有回调的采用回掉处理
  • 服务端没有回调的,按照commandid处理

消息的处理都是在相关的管理器类实例内完成

该存库的存库,该更新内存的,更新内存,然后发送事件总线更新ui  或者通知service中的相关订阅者,完成业务逻辑的数据相关处理

相关网址:

大数据/数据挖掘/推荐系统/机器学习相关资源

$
0
0

Share my personal resources,本文贡献者为Zhe Yu

书籍

各种书~各种ppt~更新中~ http://pan.baidu.com/s/1EaLnZ

机器学习经典书籍小结 http://www.cnblogs.com/snake-hand/archive/2013/06/10/3131145.html

机器学习&深度学习经典资料汇总 http://www.thebigdata.cn/JiShuBoKe/13299.html

视频

浙大数据挖掘系列 http://v.youku.com/v_show/id_XNTgzNDYzMjg=.html?f=2740765

用Python做科学计算 http://www.tudou.com/listplay/fLDkg5e1pYM.html

R语言视频 http://pan.baidu.com/s/1koSpZ

Hadoop视频 http://pan.baidu.com/s/1b1xYd

42区 . 技术 . 创业 . 第二讲 http://v.youku.com/v_show/id_XMzAyMDYxODUy.html

加州理工学院公开课:机器学习与数据挖掘 http://v.163.com/special/opencourse/learningfromdata.html

QQ群

机器学习&模式识别 246159753

数据挖掘机器学习 236347059

推荐系统 274750470

36大数据  80958753

Github

推荐系统

推荐系统开源软件列表汇总和评点 http://in.sdo.com/?p=1707

Mrec(Python) https://github.com/mendeley/mrec

Crab(Python) https://github.com/muricoca/crab

Python-recsys(Python) https://github.com/ocelma/python-recsys

CofiRank(C++) https://github.com/markusweimer/cofirank

GraphLab(C++) https://github.com/graphlab-code/graphlab

EasyRec(Java) https://github.com/hernad/easyrec

Lenskit(Java) https://github.com/grouplens/lenskit

Mahout(Java) https://github.com/apache/mahout

Recommendable(Ruby) https://github.com/davidcelis/recommendable

NLTK https://github.com/nltk/nltk

Pattern https://github.com/clips/pattern

Pyrallel https://github.com/pydata/pyrallel

Theano https://github.com/Theano/Theano

Pylearn2 https://github.com/lisa-lab/pylearn2

TextBlob https://github.com/sloria/TextBlob

MBSP https://github.com/clips/MBSP

Gensim https://github.com/piskvorky/gensim

Langid.py https://github.com/saffsd/langid.py

Jieba https://github.com/fxsjy/jieba

xTAS https://github.com/NLeSC/xtas

NumPy https://github.com/numpy/numpy

SciPy https://github.com/scipy/scipy

Matplotlib https://github.com/matplotlib/matplotlib

scikit-learn https://github.com/scikit-learn/scikit-learn

Pandas https://github.com/pydata/pandas

MDP http://mdp-toolkit.sourceforge.net/

PyBrain https://github.com/pybrain/pybrain

PyML http://pyml.sourceforge.net/

Milk https://github.com/luispedro/milk

PyMVPA https://github.com/PyMVPA/PyMVPA

博客

周涛 http://blog.sciencenet.cn/home.php?mod=space&uid=3075

Greg Linden http://glinden.blogspot.com/

Marcel Caraciolo http://aimotion.blogspot.com/

RsysChina http://weibo.com/p/1005051686952981

推荐系统人人小站 http://zhan.renren.com/recommendersystem

阿稳 http://www.wentrue.net

梁斌 http://weibo.com/pennyliang

刁瑞 http://diaorui.net

guwendong http://www.guwendong.com

xlvector http://xlvector.net

懒惰啊我 http://www.cnblogs.com/flclain/

free mind http://blog.pluskid.org/

lovebingkuai http://lovebingkuai.diandian.com/

LeftNotEasy http://www.cnblogs.com/LeftNotEasy

LSRS 2013 http://graphlab.org/lsrs2013/program/

Google小组 https://groups.google.com/forum/#!forum/resys

Journal of Machine Learning Research http://jmlr.org/

在线的机器学习社区 http://www.52ml.net/16336.html

清华大学信息检索组 http://www.thuir.cn

我爱自然语言处理 http://www.52nlp.cn/

36大数据 http://www.36dsj.com/

文章

心中永远的正能量 http://blog.csdn.net/yunlong34574

机器学习最佳入门学习资料汇总 http://article.yeeyan.org/view/22139/410514

Books for Machine Learning with R http://www.52ml.net/16312.html

是什么阻碍了你的机器学习目标? http://www.52ml.net/16436.htm

推荐系统初探 http://yongfeng.me/attach/rs-survey-zhang-slices.pdf

推荐系统中协同过滤算法若干问题的研究 http://pan.baidu.com/s/1bnjDBYZ

Netflix 推荐系统:第一部分 http://blog.csdn.net/bornhe/article/details/8222450

Netflix 推荐系统:第二部分 http://blog.csdn.net/bornhe/article/details/8222497

探索推荐引擎内部的秘密 http://www.ibm.com/developerworks/cn/web/1103_zhaoct_recommstudy1/index.html

推荐系统resys小组线下活动见闻2009-08-22 http://www.tuicool.com/articles/vUvQVn

Recommendation Engines Seminar Paper, Thomas Hess, 2009: 推荐引擎的总结性文章http://www.slideshare.net/antiraum/recommender-engines-seminar-paper

Toward the Next Generation of Recommender Systems: A Survey of the State-of-the-Art and Possible Extensions, Adomavicius, G.; Tuzhilin, A., 2005 http://dl.acm.org/citation.cfm?id=1070751

A Taxonomy of RecommenderAgents on the Internet, Montaner, M.; Lopez, B.; de la Rosa, J. L., 2003http://www.springerlink.com/index/KK844421T5466K35.pdf

A Course in Machine Learning http://ciml.info/

基于mahout构建社会化推荐引擎 http://www.doc88.com/p-745821989892.html

个性化推荐技术漫谈 http://blog.csdn.net/java060515/archive/2007/04/19/1570243.aspx

Design of Recommender System http://www.slideshare.net/rashmi/design-of-recommender-systems

How to build a recommender system http://www.slideshare.net/blueace/how-to-build-a-recommender-system-presentation

推荐系统架构小结 http://blog.csdn.net/idonot/article/details/7996733

System Architectures for Personalization and Recommendation http://techblog.netflix.com/2013/03/system-architectures-for.html

The Netflix Tech Blog http://techblog.netflix.com/

百分点推荐引擎——从需求到架构http://www.infoq.com/cn/articles/baifendian-recommendation-engine

推荐系统 在InfoQ上的内容 http://www.infoq.com/cn/recommend

推荐系统实时化的实践和思考 http://www.infoq.com/cn/presentations/recommended-system-real-time-practice-thinking

质量保证的推荐实践 http://www.infoq.com/cn/news/2013/10/testing-practice/

推荐系统的工程挑战 http://www.infoq.com/cn/presentations/Recommend-system-engineering

社会化推荐在人人网的应用 http://www.infoq.com/cn/articles/zyy-social-recommendation-in-renren/

利用20%时间开发推荐引擎 http://www.infoq.com/cn/presentations/twenty-percent-time-to-develop-recommendation-engine

使用Hadoop和 Mahout实现推荐引擎 http://www.jdon.com/44747

SVD 简介 http://www.cnblogs.com/FengYan/archive/2012/05/06/2480664.html

Netflix推荐系统:从评分预测到消费者法则 http://blog.csdn.net/lzt1983/article/details/7696578

solr5 配置 与 创建core

$
0
0

1. 准备安装包(保证tomat能正常启动)

   solr5.0

   tomcat-7.0.41

   JDK6

 

2 配置部署solr

  2.1 启动tomcat

  2.2 将solr/server/webapps/solr.war  拷贝到tomcat的webapps下。tomat会自动解压发布。

  2.3 停止tomcat,将solr.war删除。webapps下会有solr文件夹。

  2.4 在tomcat\webapps\solr下创建solr_home

  2.5 修改tomcat/webapps/solr/WEB-INF/web.xml,将 <env-entry>节点取消注释。

  2.6 将solr\server\lib\ext中的所有jar包copy到tomcat/webapps的solr/WEB-INF/lib下

       将solr\server\resources下的log4j.properties放到solr/WEB-INF/classes/下,

       如果没有classes文件夹则新建一个。

现在启动tomcat,访问http://127.0.0.1:8080/solr你会看到solradmin的界面

 

3 创建core

  3.1 关闭tomcat

  3.2 将solr\dist中的solr-dataimporthandler、solr-dataimporthandler-extras的jar包

       copy到tomcat/webapps的solr/WEB-INF/lib下

  3.3 在tomcat\webapps\solr\solr_home下创建ins文件夹(名称与下图的instanceDir一致)

  3.4 在ins文件夹下创建data和conf文件夹

  3.5 将solr\example\example-DIH\solr\solr\conf所有文件和文件夹都copy到tomcat\webapps\solr\solr_home\ins\conf下

  3.6 启动tomcat,访问solr,创建core

 3.7 ADD CORE成功后如下图所示

 

      

 



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


ITeye推荐



京东商品详情页碎碎念

$
0
0

在之前的两篇文章《 构建需求响应式亿级商品详情页》和《 京东商品详情页服务闭环实践》已经详细介绍了整个系统的架构设计和实现思路。本篇将介绍下杂七杂八的一些实践:

  • 静态化
  • 突发流量
  • 恶意访问
  • 托底数据
  • 超时时间/重试
  • CDN回源
  • 监控和报警
  • 日志

 

静态化

我个人总结为:数据静态化、页面片段静态化、页面静态化;数据静态化即把相关数据聚合为一个大数据,这样比如获取数据时只需要一次获取即可,好处是减少多次获取带来的性能开销;页面片段静态化即整个大页面按照不同的维度进行分拆,生成一些页面片段,然后通过SSI(服务端包含技术)将多个页面片段合并输出,比如商品详情页可以分为主框架、面包屑、商家信息、商品介绍、规格参数等页面片段,可以存储到磁盘或者分布式文件系统,存储到磁盘需要注意小文件造成的随机读写变多了和一些文件系统对inode数的限制;而页面静态化是把整个大页面生成静态页,缺点是页面一部分变更需要更新整个页面;其中数据静态化最灵活,可以实现数据和模板的分离,模板可以随意变化,适合经常变更的业务。

 

突发流量

对于突发流量,我这边系统的一般解决方案:高效缓存、自动降级、减少回源量;高效缓存可以参考《 构建需求响应式亿级商品详情页》和《 京东商品详情页服务闭环实践》中的缓存实践;而自动降级也在这两篇文章中讲到了,不再重复。

 

减少回源量可以通过一致性哈希、非阻塞锁、304响应来实现;通过一致性哈希可以将相同的请求打到相同的服务器,提升缓存命中率,而轮训会造成缓存命中率低;非阻塞锁即比如100个人同时请求一个页面时,首先让一个回源到后端系统进行处理,假设超时时间是100ms,如果100ms内返回了内容,则这100个人直接返回这一份内容即可,如果100ms后端系统没能返回,这100个请求会全部打到后端系统,也就是说如果后端系统响应快则回源量减少,否则回源量不会变少。

 

对于304可以通过两种机制实现,一种是业务系统提供变更时间,然后去比对是否变更,如果没有变更则直接返回304,这样只需要对比变更时间即可;另一个是设置一个容忍时间,比如10s,那么10s内的请求都返回304,不调用业务系统。对于秒杀业务设置10s的容忍时间会减少很多回源量,减少突发流量打挂后端业务系统。

 

恶意访问

对于恶意方案可以通过:提升缓存命中率,减少回源量、限流、导流到隔离的分组、N页以后的请求做特殊处理,如降低请求速度。提升缓存命中率或者所有数据都缓存/SSD,这样只要预估好流量,一般就不怕刷;另外可以减少回源量,比如使用多级缓存、爬虫做特殊处理等;对于一些请求还是需要做限流,限流可以按照连接数、请求数、流量、用户进行限流,对于缓存未命中的需要回源查数据库之类的我们需要限流,而查询缓存的请求可以根据实际情况进行限流处理;对于一些恶意的请求可能是通过小区宽带过来的,我们不能完全拒绝掉该IP,可以考虑将这些流量导到隔离的分组,比如进行慢速处理;还有一些列表页相关的应用,可以考虑对N页以后的请求做特殊处理,比如慢速处理或者根据实际调用量返回一些过期缓存数据。

 

托底数据

所谓托底数据即假设正常业务处理失败了,不能返回给用户一个503错误页,可以进行有损降级处理,比如根据场景返回一些快过期或已过期数据;另外可以进行部分有损服务而不是所有。比如请求一个用户推荐时,假设用户推荐没出来我们可以返回默认的推荐数据或者历史的推荐数据。还有如CDN缓存的,可以在出问题时返回历史数据;或者使用html5 localstorage存储;还可以通过两个分离的域名,一个失败后,自动调用另一个拿托底数据。

 

超时时间/重试

对于一个系统来说,超时时间是必须设置的,主要有如TCP连接/读/写超时时间、连接池超时时间,还有相关的重试时机/次数;对于一个网络服务,需要根据实际情况设置TCP连接/读/写超时时间,如果不设置很可能会在网络出问题时服务直接挂断,比如我们连接Redis都设置在150ms以内;还有如果使用Nginx,还需要考虑Nginx超时时间、upstream超时时间和业务超时时间,假设Nginx超时时间是5s、upstream超时时间是6s,而业务的超时时间是8s,那么假设业务处理了7s,那么upstream超时时间到了需要进行下一个upstream的重试,但是Nginx总的超时时间是5s,所以就无法重试了;连接池也需要设置获取连接的等待时间,如果不设置会有很多线程一直在等待,之前写自己实现连接池时,会去发现是否网络错误,如果网络错误就没必要等待连接了,而立即失败即可;还需要考虑服务失败重试时机,比如是立即重试,还是指数式重试;还有重试次数,是一次性重试三次还是指数式等待时间后进行一次次的重试;比如HttpClient(DefaultHttpRequestRetryHandler)默认会立即进行三次重试。 

 

CDN回源

对于CDN减少回源的策略有非阻塞锁、爬虫不回源,返回历史数据、版本化等;对于版本化的意思是对于一些内容可以通过版本化机制设置更长的超时时间,而且固定URL顺序,这样相同的URL请求只要版本不变就会更有效的命中CDN数据;版本可以通过推送机制通知相关系统;比如评价数据的版本化,可以每隔几分钟推送变更了版本 的商品更新版本号。

 

监控和报警

对于监控我们一般监控CPU/内存/磁盘、应用实例存活、调用量/响应时间/可用率这些信息,可以根据系统状况设置一些参数的阀值,比如可用率(系统异常)小于80%则告警,这样可以及时发现系统问题并解决。

 

日志

对于日志我们一般需要经常收集记录和查看Nginx日志(访问日志、错误日志)、应用日志(业务日志、异常日志、OOM堆/堆栈日志)、监控日志(调用量、响应时间、可用率)、系统日志。Nginx访问日志可以记录IP、UA、Referer等信息以便发现恶意访问的一些线索,记录request_time、response_time来发现是否存在一些慢速请求;而Nginx错误日志查看是否存在超时或者一些服务出问题了;应用业务日志用来排查业务逻辑是否正确的,而应用异常日志用来发现什么时间、什么位置、哪个类的哪个方法出现了什么问题,以便故障排查,还有如Java应用OOM时的堆/堆栈日志也要存好了;监控日志用来记录服务的一些吞吐量和性能数据;另外需要经常查看系统日志,如之前遇到过应用大量timeout情况,查看dmsg发现存在nf_conntrack: table full, dropping packet,让运维把防火墙关掉即可。

 

其他

为了发现是哪台服务器出现了问题,我们都要在响应响应头记录服务器真实IP,这样出问题后,直接定位到哪台服务器出问题了;对于多机房业务尽量使用智能DNS,即一个机房的服务尽量调用一个机房的服务,减少跨机房调用;在没有进行Docker容器化之前,我们还可以减少跨交换机、跨机柜调用;对于整个系统我们无法保证整个系统不出现脏数据,所以需要提供刷脏数据的接口,以便出现问题时进行数据的更新或删除。

 

 

 

 



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


ITeye推荐



京东商品详情页服务闭环实践

$
0
0

该文章是根据OpenResty Con 2015技术大会的演讲《 Nginx+Lua在京东商品详情页的大规模应用》细化而来,希望对大家有用。

 

京东商品详情页技术方案在之前《 构建需求响应式亿级商品详情页》这篇文章已经为大家揭秘了,接下来为大家揭秘下双十一抗下几十亿流量的商品详情页统一服务架构,这次双十一整个商品详情页没有出现不服务的情况,服务非常稳定。统一服务提供了:促销和广告词合并服务、库存状态/配送至服务、延保服务、试用服务、推荐服务、图书相关服务、详情页优惠券服务、今日抄底服务等服务支持;这些服务中有我们自己做的服务实现,而有些是简单做下代理或者接口做了合并输出到页面,我们聚合这些服务到一个系统的目的是打造服务闭环,优化现有服务,并为未来需求做准备,跟着自己的方向走,而不被别人乱了我们的方向。

 

大家在页面中看到的c.3.cn/c0.3.cn/c1.3.cn/cd.jd.com请求都是统一服务的入口。

 

为什么需要统一服务

商品详情页虽然只有一个页面,但是依赖的服务众多,我们需要把控好入口,一统化管理。这样的好处:统一管理和监控,出问题可以统一降级;可以把一些相关接口合并输出,减少页面的异步加载请求;一些前端逻辑后移到服务端,前端只做展示,不进行逻辑处理。

 

有了它,所有入口都在我们服务中,我们可以更好的监控和思考我们页面的服务,让我们能运筹于帷幄之中,决胜于千里之外。在设计一个高度灵活的系统时,要想着当出现问题时怎么办:是否可降级、不可降级怎么处理、是否会发送滚雪球问题、如何快速响应异常;完成了系统核心逻辑只是保证服务能工作,服务如何更好更有效或者在异常情况下能正常工作也是我们要深入思考和解决的问题。

 

整体架构


 

 

整体流程:

1、请求首先进入Nginx,Nginx调用Lua进行一些前置逻辑处理,如果前置逻辑不合法直接返回;然后查询本地缓存,如果命中直接返回数据;

2、如果本地缓存不命中数据,则查询分布式Redis集群,如果命中数据,则直接返回;

3、如果分布式Redis集群不命中,则会调用Tomcat进行回源处理;然后把结果异步写入Redis集群,并返回。

如上是整个逻辑流程,可以看到我们在Nginx这一层做了很多前置逻辑处理,以此来减少后端压力,另外我们Redis集群分机房部署,如下所示:



 

即数据会写一个主集群,然后通过主从方式把数据复制到其他机房,而各个机房读自己的集群;此处没有在各个机房做一套独立的集群来保证机房之间没有交叉访问,这样做的目的是保证数据一致性。

 

在这套新架构中,我们可以看到Nginx+Lua已经是我们应用的一部分,我们在实际使用中,也是把它做为项目开发,做为应用进行部署。

 

一些架构思路和总结

我们主要遵循如下几个原则设计系统架构:

  • 两种读服务架构模式
  • 本地缓存
  • 多级缓存
  • 统一入口/服务闭环
  • 引入接入层
  • 前端业务逻辑后置
  • 前端接口服务端聚合
  • 服务隔离

  

两种读服务架构模式

1、读取分布式Redis数据架构



 

可以看到Nginx应用和Redis单独部署,这种方式是一般应用的部署模式,也是我们统一服务的部署模式,此处会存在跨机器、跨交换机或跨机柜读取Redis缓存的情况,但是不存在跨机房情况,因为通过主从把数据复制到各个机房。如果对性能要求不是非常苛刻,可以考虑这种架构,比较容易维护。

 

2、读取本地Redis数据架构



 

可以看到Nginx应用和Redis集群部署在同一台机器,这样好处可以消除跨机器、跨交换机或跨机柜,甚至跨机房调用。如果本地Redis集群不命中, 还是回源到Tomcat集群进行取数据。此种方式可能受限于TCP连接数,可以考虑使用unix domain socket套接字减少本机TCP连接数。如果单机内存成为瓶颈(比如单机内存最大256GB),就需要路由机制来进行Sharding,比如按照商品尾号Sharding,Redis集群一般采用树状结构挂主从部署。

 

 

本地缓存

我们把Nginx作为应用部署,因此我们大量使用Nginx共享字典作为本地缓存,Nginx+Lua架构中,使用HttpLuaModule模块的shared dict做本地缓存( reload不丢失)或内存级Proxy Cache,提升缓存带来的性能并减少带宽消耗;另外我们使用一致性哈希(如商品编号/分类)做负载均衡内部对URL重写提升命中率。

 

我们在缓存数据时采用了维度化存储缓存数据,增量获取失效缓存数据(比如10个数据,3个没命中本地缓存,只需要取这3个即可);维度如商家信息、店铺信息、商家评分、店铺头、品牌信息、分类信息等;比如我们本地缓存30分钟,调用量减少差不多3倍。

另外我们使用一致性哈希+本地缓存,如库存数据缓存5秒,平常命中率:本地缓存25%;分布式Redis28%;回源47%;一次普通秒杀活动命中率:本地缓存 58%;分布式Redis 15%;回源27%;而某个服务使用一致哈希后命中率提升10%;对URL按照规则重写作为缓存KEY,去随机,即页面URL不管怎么变都不要让它成为缓存不命中的因素。

 

多级缓存

对于读服务,我们在设计时会使用多级缓存来尽量减少后端服务压力,在统一服务系统中,我们设计了四级缓存,如下所示:

 

 

1.1、首先在接入层,会使用Nginx本地缓存,这种前端缓存主要目的是抗热点;根据场景来设置缓存时间;

1.2、如果Nginx本地缓存不命中,接着会读取各个机房的分布式从Redis缓存集群,该缓存主要是保存大量离散数据,抗大规模离散请求,比如使用一致性哈希来构建Redis集群,即使其中的某台机器出问题,也不会出现雪崩的情况;

1.3、如果从Redis集群不命中,Nginx会回源到Tomcat;Tomcat首先读取本地堆缓存,这个主要用来支持在一个请求中多次读取一个数据或者该数据相关的数据;而其他情况命中率是非常低的,或者缓存一些规模比较小但用的非常频繁的数据,如分类,品牌数据;堆缓存时间我们设置为Redis缓存时间的一半;

1.4、如果Java堆缓存不命中,会读取主Redis集群,正常情况该缓存命中率非常低,不到5%;读取该缓存的目的是防止前端缓存失效之后的大量请求的涌入,导致我们后端服务压力太大而雪崩;我们默认开启了该缓存,虽然增加了几毫秒的响应时间,但是加厚了我们的防护盾,使服务更稳当可靠。此处可以做下改善,比如我们设置一个阀值,超过这个阀值我们才读取主Redis集群,比如Guava就有RateLimiter API来实现。

 

统一入口/服务闭环

在《 构建需求响应式亿级商品详情页》中已经讲过了数据异构闭环的收益,在统一服务中我们也遵循这个设计原则,此处我们主要做了两件事情:

1、数据异构,如判断库存状态依赖的套装、配件关系我们进行了异构,未来可以对商家运费等数据进行异构,减少接口依赖;

2、服务闭环,所有单品页上用到的核心接口都接入统一服务;有些是查库/缓存然后做一些业务逻辑,有些是http接口调用然后进行简单的数据逻辑处理;还有一些就是做了下简单的代理,并监控接口服务质量。

 

引入Nginx接入层

我们在设计系统时需要把一些逻辑尽可能前置以此来减轻后端核心逻辑的压力,另外如服务升级/服务降级能非常方便的进行切换,在接入层我们做了如下事情:

  • 数据校验/过滤逻辑前置、缓存前置、业务逻辑前置
  • 降级开关前置
  • AB测试
  • 灰度发布/流量切换
  • 监控服务质量
  • 限流

 

数据校验/过滤逻辑前置

我们服务有两种类型的接口:一种是用户无关的接口,另一种则是用户相关的接口;因此我们使用了两种类型的域名c.3.cn/c0.3.cn/c1.3.cn和cd.jd.com;当我们请求cd.jd.com会带着用户cookie信息到服务端;在我们服务器上会进行请求头的处理,用户无关的所有数据通过参数传递,在接入层会丢弃所有的请求头(保留gzip相关的头);而用户相关的会从cookie中解出用户信息然后通过参数传递到后端;也就是后端应用从来就不关心请求头及Cookie信息,所有信息通过参数传递。

请求进入接入层后,会对参数进行校验,如果参数校验不合法直接拒绝这次请求;我们对每个请求的参数进行了最严格的数据校验处理,保证数据的有效性。如下所示,我们对关键参数进行了过滤,如果这些参数不合法就直接拒绝请求。

 

另外我们还会对请求的参数进行过滤然后重新按照固定的模式重新拼装URL调度到后端应用,此时URL上的参数是固定的而且是有序的,可以按照URL进行缓存。

 

缓存前置

我们把很多缓存前置到了接入层,来进行热点数据的削峰,而且配合一致性哈希可能提升缓存的命中率。在缓存时我们按照业务来设置缓存池,减少相互之间的影响和提升并发。我们使用Lua读取共享字典来实现本地缓存。

 

业务逻辑前置

我们在接入层直接实现了一些业务逻辑,原因是当在高峰时出问题,可以在这一层做一些逻辑升级;我们后端是Java应用,当修复逻辑时需要上线,而一次上线可能花费数十秒时间启动应用,重启应用后Java应用JIT的问题会存在性能抖动的问题,可能因为重启造成服务一直启动不起来的问题;而在Nginx中做这件事情,改完代码推送到服务器,重启只需要秒级,而且不存在抖动的问题。这些逻辑都是在Lua中完成。

 

降级开关前置

我们降级开关分为这么几种:接入层开关和后端应用开关、总开关和原子开关;我们在接入层设置开关的目的是防止降级后流量还无谓的打到后端应用;总开关是对整个服务降级,比如库存服务默认有货;而原子开关时整个服务中的其中一个小服务降级,比如库存服务中需要调用商家运费服务,如果只是商家运费服务出问题了,此时可以只降级商家运费服务。另外我们还可以根据服务重要程度来使用超时自动降级机制。

我们使用init_by_lua_file初始化开关数据,共享字典存储开关数据,提供API进行开关切换(switch_get(“stock.api.not.call”) ~= “1”)。可以实现:秒级切换开关、增量式切换开关(可以按照机器组开启,而不是所有都开启)、功能切换开关、细粒度服务降级开关、非核心服务可以超时自动降级。

 

比如双十一期间我们有些服务出问题了,我们进行过大服务和小服务的降级操作,这些操作对用户来说都是无感知的。

 

AB测试

对于服务升级,最重要的就是能做AB测试,然后根据AB测试的结果来看是否切新服务;而有了接入层非常容易进行这种AB测试;不管是上线还是切换都非常容易。可以在Lua中根据请求的信息调用不同的服务或者upstream分组即可完成AB测试。

 

灰度发布/流量切换

对于一个灵活的系统来说,能随时进行灰度发布和流量切换是非常重要的一件事情,比如验证新服务器是否稳定,或者验证新的架构是否比老架构更优秀,有时候只有在线上跑着才能看出是否有问题;我们在接入层可以通过配置或者写Lua代码来完成这件事情,灵活性非常好。可以设置多个upstream分组,然后根据需要切换分组即可。

 

监控服务质量

对于一个系统最重要的是要有双眼睛能盯着系统来尽可能早的发现问题,我们在接入层会对请求进行代理,记录status、request_time、response_time来监控服务质量,比如根据调用量、状态码是否是200、响应时间来告警。

 

限流

我们系统中存在的主要限流逻辑是:对于大多数请求按照IP请求数限流,对于登陆用户按照用户限流;对于读取缓存的请求不进行限流,只对打到后端系统的请求进行限流。还可以限制用户访问频率,比如使用ngx_lua中的ngx.sleep对请求进行休眠处理,让刷接口的速度降下来;或者种植cookie token之类的,必须按照流程访问。当然还可以对爬虫/刷数据的请求返回假数据来减少影响。

 

前端业务逻辑后置

前端JS应该尽可能少的业务逻辑和一些切换逻辑,因为前端JS一般推送到CDN,假设逻辑出问题了,需要更新代码上线,推送到CDN然后失效各个边缘CDN节点;或者通过版本号机制在服务端模板中修改版本号上线,这两种方式都存在效率问题,假设处理一个紧急故障用这种方式处理完了可能故障也恢复了。因此我们的观点是前端JS只拿数据展示,所有或大部分逻辑交给后端去完成,即静态资源CSS/JS CDN,动态资源JSONP;前端JS瘦身,业务逻辑后置。

在双十一期间我们的某些服务出问题了,不能更新商品信息,此时秒杀商品需要打标处理,因此我们在服务端完成了这件事情,整个处理过程只需要几十秒就能搞定,避免了商品不能被秒杀的问题。而如果在JS中完成需要耗费非常长的时间,因为JS在客户端还有缓存时间,而且一般缓存时间非常长。

 

前端接口服务端聚合

商品详情页上依赖的服务众多,一个类似的服务需要请求多个不相关的服务接口,造成前端代码臃肿,判断逻辑众多;而我无法忍受这种现状,我想要的结果就是前端异步请求我的一个API,我把相关数据准备好发过去,前端直接拿到数据展示即可;所有或大部分逻辑在服务端完成而不是在客户端完成;因此我们在接入层使用Lua协程机制并发调用多个相关服务然后最后把这些服务进行了合并。

 

比如推荐服务:最佳组合、推荐配件、优惠套装;通过

http://c.3.cn/recommend?methods=accessories,suit,combination&sku=1159330&cat=6728,6740,12408&lid=1&lim=6进行请求获取聚合的数据,这样原来前端需要调用三次的接口只需要一次就能吐出所有数据。

我们对这种请求进行了API封装,如下所示:


 

比如库存服务,判断商品是否有货需要判断:1、主商品库存状态、2、主商品对应的套装子商品库存状态、主商品附件库存状态及套装子商品附件库存状态;套装商品是一个虚拟商品,是多个商品绑定在一起进行售卖的形式。如果这段逻辑放在前段完成,需要多次调用库存服务,然后进行组合判断,这样前端代码会非常复杂,凡是涉及到调用库存的服务都要进行这种判断;因此我们把这些逻辑封装到服务端完成;前端请求http://c0.3.cn/stock?skuId=1856581&venderId=0&cat=9987,653,655&area=1_72_2840_0&buyNum=1&extraParam={%22originid%22:%221%22}&ch=1&callback=getStockCallback,然后服务端计算整个库存状态,而前端不需要做任何调整。在服务端使用Lua协程并发的进行库存调用,如下图所示:


 

比如今日抄底服务,调用接口太多,如库存、价格、促销等都需要调用,因此我们也使用这种机制把这几个服务在接入层合并为一个大服务,对外暴露:http://c.3.cn/today?skuId=1264537&area=1_72_2840_0&promotionId=182369342&cat=737,752,760&callback=jQuery9364459&_=1444305642364。

 

我们目前合并的主要有:促销和广告词合并、配送至相关服务合并。而未来这些服务都会合并,会在前端进行一些特殊处理,比如设置超时,超时后自动调用原子接口;接口吐出的数据状态码不对,再请求一次原子接口获取相关数据。

 

服务隔离

服务隔离的目的是防止因为某些服务抖动而造成整个应用内的所有服务不可用,可以分为:应用内线程池隔离、部署/分组隔离、拆应用隔离。

应用内线程池隔离,我们采用了Servlet3异步化,并为不同的请求按照重要级别分配线程池,这些线程池是相互隔离的,我们也提供了监控接口以便发现问题及时进行动态调整,该实践可以参考《 商品详情页系统的Servlet3异步化实践》。

部署/分组隔离,意思是为不同的消费方提供不同的分组,不同的分组之间不相互影响,以免因为大家使用同一个分组导致有些人乱用导致整个分组服务不可用。

拆应用隔离,如果一个服务调用量巨大,那我们便可以把这个服务单独拆出去,做成一个应用,减少因其他服务上线或者重启导致影响本应用。

 

相关文章 

 



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


ITeye推荐



腾讯首次公布微信数据(完整版)这才叫大数据!

$
0
0
     在2015腾讯全球合作伙伴大会「互联网+微信」的分论坛上,微信官方第一次公开了微信用户数据。

  60% 微信用户是年轻人(15 - 29 岁);

  年轻人平均有 128 个好友;工作后好友会增加 20%;

  58% 异地通话是年轻人;

  年轻人购物高峰是在早上的 10 点和晚上 10 点;

  微信 9 月平均日登录用户达到 5.7 亿,这个数据略惊人。

  

  在城市渗透率方面,一线城市渗透率达到 93%,二线城市为 69%。在三到五线城市,微信渗透率不到50%,仍然较大的增长空间。

  

  用户活跃高峰相比去年的晚上 10 点 30 分提前到了 10 点。

  

  发红包参与人数最多的是中秋节,其次是七夕节。以后是不是一到节日就到发红包。「11.11」快到了,请发红包慰问小编我!

  

  用户分类上90后爱看娱乐八卦,80后喜欢国家大事,60后热衷鸡汤文化。70后干嘛去了......

  

  微信眼中的的「典型用户的一天」。

  

  每天通话280,000,000 分钟,平均每个用户是多少分钟,帮我算算吧?

  想知道你是第几位微信红包用户?长按识别二维码吧。

  

  《2015微信生活白皮书》完整版如下:

  

  

  

  

  绿点越亮,使用微信通话的数量也就越多。

  

  

  

  西湖是最微信签到最多的地方;香港是微信用户境外签到最多的地方。

  

  

  

  

  

  

  

  

  

  

  

  

  


淘宝数据产品技术架构分析

$
0
0

淘宝网拥有国内最具商业价值的海量数据。截至当前,每天有超过30亿的店铺、商品浏览记录,10亿在线商品数,上千万的成交、收藏和评价数据。如何从这些数据中挖掘出真正的商业价值,进而帮助淘宝、商家进行企业的数据化运营,帮助消费者进行理性的购物决策,是淘宝数据平台与产品部的使命。

为此,我们进行了一系列数据产品的研发,比如为大家所熟知的量子统计、数据魔方和淘宝指数等。尽管从业务层面来讲,数据产品的研发难度并不高;但在“海量”的限定下,数据产品的计算、存储和检索难度陡然上升。本文将以数据魔方为例,向大家介绍淘宝在海量数据产品技术架构方面的探索。  

淘宝海量数据产品技术架构

数据产品的一个最大特点是数据的非实时写入,正因为如此,我们可以认为,在一定的时间段内,整个系统的数据是只读的。这为我们设计缓存奠定了非常重要的基础。

图1 淘宝海量数据产品技术架构

按照数据的流向来划分,我们把淘宝数据产品的技术架构分为五层(如图1所示),分别是数据源、计算层、存储层、查询层和产品层。位于架构顶端的是我们的数据来源层,这里有淘宝主站的用户、店铺、商品和交易等数据库,还有用户的浏览、搜索等行为日志等。这一系列的数据是数据产品最原始的生命力所在。

在数据源层实时产生的数据,通过淘宝自主研发的数据传输组件DataX、DbSync和Timetunnel准实时地传输到一个有1500个节点的Hadoop集群上,这个集群我们称之为“云梯”,是计算层的主要组成部分。在“云梯”上,我们每天有大约40000个作业对1.5PB的原始数据按照产品需求进行不同的MapReduce计算。这一计算过程通常都能在凌晨两点之前完成。相对于前端产品看到的数据,这里的计算结果很可能是一个处于中间状态的结果,这往往是在数据冗余与前端计算之间做了适当平衡的结果。

不得不提的是,一些对实效性要求很高的数据,例如针对搜索词的统计数据,我们希望能尽快推送到数据产品前端。这种需求再采用“云梯”来计算效率将是比较低的,为此我们做了流式数据的实时计算平台,称之为“银河”。“银河”也是一个分布式系统,它接收来自TimeTunnel的实时消息,在内存中做实时计算,并把计算结果在尽可能短的时间内刷新到NoSQL存储设备中,供前端产品调用。

容易理解,“云梯”或者“银河”并不适合直接向产品提供实时的数据查询服务。这是因为,对于“云梯”来说,它的定位只是做离线计算的,无法支持较高的性能和并发需求;而对于“银河”而言,尽管所有的代码都掌握在我们手中,但要完整地将数据接收、实时计算、存储和查询等功能集成在一个分布式系统中,避免不了分层,最终仍然落到了目前的架构上。

为此,我们针对前端产品设计了专门的存储层。在这一层,我们有基于MySQL的分布式关系型数据库集群MyFOX和基于HBase的NoSQL存储集群Prom,在后面的文字中,我将重点介绍这两个集群的实现原理。除此之外,其他第三方的模块也被我们纳入存储层的范畴。

存储层异构模块的增多,对前端产品的使用带来了挑战。为此,我们设计了通用的数据中间层——glider——来屏蔽这个影响。glider以HTTP协议对外提供restful方式的接口。数据产品可以通过一个唯一的URL获取到它想要的数据。

以上是淘宝海量数据产品在技术架构方面的一个概括性的介绍,接下来我将重点从四个方面阐述数据魔方设计上的特点。  

关系型数据库仍然是王道

关系型数据库(RDBMS)自20世纪70年代提出以来,在工业生产中得到了广泛的使用。经过三十多年的长足发展,诞生了一批优秀的数据库软件,例如Oracle、MySQL、DB2、Sybase和SQL Server等。

图2 MyFOX中的数据增长曲线

尽管相对于非关系型数据库而言,关系型数据库在分区容忍性(Tolerance to Network Partitions)方面存在劣势,但由于它强大的语义表达能力以及数据之间的关系表达能力,在数据产品中仍然占据着不可替代的作用。

淘宝数据产品选择MySQL的MyISAM引擎作为底层的数据存储引擎。在此基础上,为了应对海量数据,我们设计了分布式MySQL集群的查询代理层——MyFOX,使得分区对前端应用透明。

图3 MyFOX的数据查询过程

目前,存储在MyFOX中的统计结果数据已经达到10TB,占据着数据魔方总数据量的95%以上,并且正在以每天超过6亿的增量增长着(如图2所示)。这些数据被我们近似均匀地分布到20个MySQL节点上,在查询时,经由MyFOX透明地对外服务(如图3所示)。

图4 MyFOX节点结构

值得一提的是,在MyFOX现有的20个节点中,并不是所有节点都是“平等”的。一般而言,数据产品的用户更多地只关心“最近几天”的数据,越早的数据,越容易被冷落。为此,出于硬件成本考虑,我们在这20个节点中分出了“热节点”和“冷节点”(如图4所示)。

顾名思义,“热节点”存放最新的、被访问频率较高的数据。对于这部分数据,我们希望能给用户提供尽可能快的查询速度,所以在硬盘方面,我们选择了每分钟15000转的SAS硬盘,按照一个节点两台机器来计算,单位数据的存储成本约为4.5W/TB。相对应地,“冷数据”我们选择了每分钟7500转的SATA硬盘,单碟上能够存放更多的数据,存储成本约为1.6W/TB。

干货 | 一文帮你盘点 2015 年投融资以及行业大势

$
0
0
作者: lydiaxin

编者注:本文来源于华兴资本,原文有删改。


2015 年,互联网与资本比以往更为深远地影响着各行各业,也深刻地改变大众生活。据 IT 桔子收录,2015 年融资事件(不含并购)有 4100 起,公布融资金额近 500 亿美元。华兴各个业务线 14 个团队超过 20 位同事对过去一年进行观察与总结,得出年终盘点报告。

报告分为领域、行业、市场和预见四个部分,包括境内资本市场、早中后期融资及 IPO、并购和投资领域以及 O2O、互联网金融、电商、互联网医疗、高科技、内容与泛娱乐、物流、社区社交、医疗等行业。

早期融资领域

2015 年是一个创业大年,也是早期公司融资数量井喷的一年。全年的天使融资项目和 A 轮融资项目成功的数量与 14 年基本持平,然而早期创业者的机遇却不如 14 年了。

移动互联网红利被「万众创业」消耗得差不多了之后,2015 年的新创业者更多地陷入了找不准方向的迷茫之中。在现有模式上的微创新,或者是针对 niche market(高度专业化市场)的细分领域创业比例大增,真正有潜力深度改变行业的创业者凤毛麟角。

与之对应的是资本市场的热度也在同步降温,资本寒冬会持续多久,寒冬期应该怎么办,这些问题逐渐成为了中关村大街上最常被讨论的热门话题。但纵观 2015 年,以下这些这些领域并没有遭受冷遇。

  • 年初:农业和工业供应链互联网化
  • 年中:医疗、体育运动行业的各种突破和创新
  • 年底:VR 技术广泛受关注

可以看出,创新活跃的领域依然是天使和早期 VC 们追逐的风口。

回顾 2015 年,受中概股在公开市场表现不佳的影响,中国新经济企业在资本市场以私募融资活动为主,同时具有以下的特征:

  • 受全球股票市场波动等因素,众多公司放缓了上市的脚步,中概股火爆不再
  • 各时期私募融资市场仍然活跃,除了整体规模增大外,单笔融资额亦大幅增长
  • 细分行业方面,O2O 和出行无疑是 2015 年最火热的两个领域,除此之外,互联网金融也在迅速崛起

并购领域

「合并」堪称 2015 年互联网行业最重要的关键词。从滴滴快的、58 赶集,到点评美团、携程去哪儿,都由相杀走向相爱。下一对儿会是谁,不免让人热议和期待。

展望 2016 年,TMT 领域并购市场的主要趋势有:

  • 回归国内资本市场将继续成为趋势。 国内市场的日益开放、多元,以及国内外市场间继续存在的估值差异,仍然是支撑境外优质 TMT 资产回归的动因,这其中将蕴含大量的私有化、拆 VIE、跨境并购以及借壳交易的机会。
  • 垂直领域的合并整合将持续发生。新经济代表着活力和市场化,资本层面的抱团取暖,企业层面的共荣共生,随着互联网垂直行业的发展日益成熟,竞争日趋激烈,通过整合并购优化资源配置的交易将持续增多。
  • 随着国内并购监管口径基本放开,境内资本市场的进一步市场化,A 股并购市场将愈发成熟。同时一系列真正意义的互联网公司登陆 A 股市场后,也会反过来促进具备商业逻辑和商业价值的并购逐渐取代之前的「市值管理驱动」,占据主流并购市场投资领域

据统计,今年前三季度国内一共成立 1411 家新基金,平均每家新基金的募资金额约 3 亿元。

展望 2016,从资本市场来看,我们认为回归国内资本市场的趋势将仍然继续,资本市场改革的实质推进将继续推动优质的境外结构企业回归。而在具体的行业判断上,我们认为以下三个方向将成为市场热点:

  • 互联网金融:传统金融市场巨大,互联网化仍处于初级阶段,渗透率仍有很大提升潜力。过去的一年里 BAT 等巨头频繁发力支付、理财等领域,提升了用户对互联网金融的接受度。互联网金融尤其是供应链金融和消费金融细分领域将成长出更多优秀的公司。
  • 企业服务:我国企业服务市场相较欧美市场仍有很大发展空间,在阿里钉钉、纷享销客、UCloud 等领先公司的带领下,2016 年移动化、云端化将成为企业服务的潮流。
  • 交易平台:过去一年垂直领域的交易平台呈现爆发式增长,获得融资的企业数从 2014 年的 16 个迅速增长到 2015 年的 94 个。我们继续看好能提升供应链效率的交易平台,相信渠道价值是任何终端产品都改变不了的重要壁垒。

行业

1.O2O

2015 年对于 O2O 领域是热闹的一年,你方唱罢我登场,伴随着此起彼伏的硝烟和火药味,精彩不断,高潮迭起。回顾其今年表现,不得不感叹互联网渗透速度之快,仿佛每个月、每周都有创新和贴心的服务冒出来,开始影响我们的工作和生活。

和前一年相比,我们观察到的行业趋势主要有以下几方面:

  • 由 GMV、业务规模(单量)导向型,向注重收入、毛利或者单位经济效益发展
  • 由真伪需求并存,向去伪存真、尊重行业规律发展
  • 由粗放型补贴,向选择性补贴甚至无补贴发展
  • 由低毛利的基础服务,向多品类、高毛利的衍生增值服务发展

行业变革方兴未艾,互联网的渗透率仍然很低,这些领域经过调整后将更回归生意本质,朝着更健康的方向发展,2016 年仍有很多新机会。

互联网金融

2015 年互联网金融领域投资热点由 P2P 裂变为消费金融和泛财富管理,作为基础设施的个人征信和大数据服务、体现产融结合的供应链金融,也是未来互联网金融的热点领域。

  • 在泛财富管理领域,2014 年我国居民金融资产总量已达 92 万亿,随着互联网技术及精神的普及,中国互联网理财正在兴起,基金、股票、保险、另类资产和海外资产等介于银行理财和 P2P 收益率之间的多元化资产是配置热点。但目前中国的互联网理财公司大多仍处于产品推销阶段,金融能力和基因都有待提高。对于流量型互联网理财平台而言,加强资产组合的开发、投资策略以及面向用户的个性化财富管理能力是竞争核心、
  • 在消费金融领域, 从趋势上看,金融产品与消费场景和上游产业链的结合进一步加深,互联网对金融产业链的渗透正在由获客渠道深入信审风控等各个环节。从竞争上看, 细分垂直领域的竞争在于特定消费场景的把控能力、对目标客群的低成本触达能力和风险识别能力。传统金融机构、互联网巨头和创业公司利用各自的优势开拓增量市场,现阶段合作多于竞争,各机构在自己的风险容忍度内不断试错,在风险和规模的动态平衡重逐渐寻找市场边界。


image8.jpg

由此可见,掌握对特定资产的风险定价能力是金融领域创业公司必须练就的基本功;同时,互联网对金融产业链的核心价值开始逐步显现,真正能够帮助金融和类金融机构提高获客、风控、资金与资产对接效率的平台更易获得资本青睐。

电商

在 2015 年末市场纷纷预测未来电商双寡头格局的同时,社会化、O2O、跨境、B2B 电商等细分领域正在进行着巨大变化。

image9.jpg

  • 社会化电商:超乎寻常的增长背后消耗的是人与人间的信誉成本。随着规则不断成熟,社会化会逐步回归理性,发挥其原本该有的杠杆效应,无论作为电商的补充渠道还是新的产品形态都具有一定价值。
  • O2O 电商:O2O 电商对执行力和效率要求极高,下半年市场对补贴掩盖低效的态度变得极为谨慎。然而,传统电商纷纷建立 O2O 渠道,BAT 下重注入场解决支付,达达迅速发展提供物流基础,美团和饿了么完成巨额融资,可以预见的是围绕本地化电商消费潜力不亚于传统电商。
  •  跨境电商:2015 年跨境电商爆发,安全,高品质,多样化成为了核心需求。跨境电商还会保持高速增长,前端会继续朝社群化、场景化的方向发展,中端通路会随着政策调整继续优化,后端由于巨头进入竞争会更加激烈,从选品、BD(商务拓展),货源组织能力的提升都将成为掌控供应链的关键。
  • B2B 电商:2015 年也是 B2B 供应链电商最为火热的一年。仔细看国内各细分供应链相比发达国家长期处于低效稳定态,体现在终端价格和源头价格的价差和中间环节的繁杂,而互联网和物流的蓬勃发展为解决信息和物品流通做好了准备。

互联网医疗

医疗行业是互联网最难改造的行业之一,主要原因包括专业性、行业相对封闭性,更重要的是最好的医疗都是「供给」稀缺,体现在好医生和好医院的稀缺性。目前各个入口都涌现出一些优秀的公司。

image10.jpg

  • 医院入口:部分企业以挂号最早入口,已经在医疗信息化和流程改造上面取得了一定的成绩。 这个领域关注的重点是接入优质医院的数量和与医院信息系统的对接程度。
  •  医生入口:互联网医疗由于其攻击的稀缺性,积累了大量优质医生资源和强粘性的企业具有较强优势,而如何聚集医生的核心是解决他们的核心诉求。未来能够帮助医生多点执业,提高医生合法性收入的创业公司将值得关注。
  • 患者入口: 医药电商未来将是一个重要的变现领域,但是发展速度取决于线上处方/网售处方药放开、医药分家的进程,该领域一些大的传统电商平台和前十大医药电商都还是有机会的。 慢性病管理也是值得关注的领域,关键在于如何深刻地理解病种和患者需求,设计出优秀的产品。

高科技

2015 年是高科技行业创业公司在业务发展和私募融资方面的进阶之年。

  • 软件领域

云计算应用与服务依然是热点,但更关注到一些传统行业的服务需求,会根据客户情况考虑私有云与公有云的架构,更加注重线下推广与线上营销的结合。收费还是免费、ToB 或是 ToD、线下推广和线上营销的商业模式中,我们更看好前者或二者相结合。

企业级服务是 2015 年的一大投资热点,该领域中的创业公司从不同方向切入,未来还将向深入和完整的解决方案扩充,有机会产生平台级企业。

未来云服务在通用基础设施或垂直行业也还有很多机会,如金融服务、大数据、智能家居、IOT 物联网等领域。

  • 硬件领域

物联化和智能化的新硬件时代到来,技术创新会驱动产品创新,人工智能和机器学习等技术,机器人和替代性的创新硬件会更受关注。在大热的 VR 和 AR(虚拟现实和增强现实)领域,硬件与软件、内容的结合很重要。

商业模式上我们会看重 创造毛利的能力,规模放量降低成本提升毛利,是常见的形式。后向收费也是锦上添花。对于硬件产品,线下体验和线上流量都很重要。

内容与泛娱乐

2015 年被视作 IP 元年。网络文学、影视、游戏、动漫等不同的内容形态互相跨界,许多「现象级」作品诞生之余,整个行业也在发生很多转变。

  •  版权正规化与付费意愿:版权大战倒逼市场趋于正规化,增加了内容创作者的创作意愿,可以让大家松一口气的是,正在成为主流的新一代用户正在以其较好的付费习惯重塑市场。未来 5 年内,内容与泛娱乐市场在放开二胎后的婴儿潮冲击到来前,面对的是以人数相对较少、支付能力相对较强的 85 后-00 后为基础的优质市场。
  • 向全年龄段全阶层进击的内容产业:与过去粗制滥造、低格调、年轻化导向严重的屌丝网生内容风格相比,2015 年内容领域高富帅连连出现,制作精良、亮点频出、进入主流影视渠道的优质作品,如《琅琊榜》《煎饼侠》等。2016 年会有更多制作成本更高,制作更加精细,内容更加丰满的产品面世。
  •   会玩很重要:具备账号体系、单个用户生命周期概念成立的内容产品,对于用户社区氛围的运营重要程度将成为新的门槛和品牌塑造的途径,强烈的品牌形象具备旺盛的生命力,基于此嫁接多种业务。

物流

2015 年物流行业风起云涌,传统物流公司在境内外资本市场上积极运作,新兴创投公司从上半年「有钱任性」的烧钱扩张到下半年随着资本收紧趋于理性。

  • 快递、零担/整车、冷链为代表的传统物流:

消费升级及电子商务驱动的「通达系」与顺丰延续高增长,民营快递寡头垄断格局已定。 零担/整车及冷链行业仍保持较为分散化的竞争格局。2015 年对传统物流企业来说,是加速踏上资本市场征程的一年,行业领头企业们都在积极布局境内外资本市场。

image12.jpg

  • 「飞猪风口」下的货运 O2O 与「最后一公里」物流: 把握计划与即时订单市场的潜在市场规模将起到关键性作用

谁将成为货运版「滴滴打车」,有些公司选择将「身子变重」从线上资源整合走向线下传统物流资产布局,而另一些选择了长途车货匹配与同城货运的「抱团取暖」。

同时「最后一公里」物流仍然是兵家必争之地。把握 B2C(同城快递、电商、外卖/下午茶、鲜花/蛋糕等) 与 C2C 这两大类别在业务中的优化配比是该赛道优胜者的获胜砝码。

社区社交

无论国内还是国外,相比移动互联网初期,最近一两年社交市场上的创业热潮急剧降温,甚至一大部分的社交产品都逃不过「火阵死」的魔咒。究其原因,一方面是由于微信 QQ 的功能完备,垄断地位难以撼动,另一方面则在于社交行业的特殊属性——产品经理对于人们内心的社交需求和冲动难以准确把握。

尽管如此,我们还是能从近期的投资案例中一窥投资市场青睐的社交/社区产品特点:

  • 社交产品

定位细分人群的社交需求: 大而全的陌生人社交已经很难做到理想的规模和留存,专注于细分人群的社交 APP 却可以另辟一块蓝海。

突出或创新的产品特征:社交软件看似五花八门玩法各异,但是十个 APP 九个像,难逃用户的三分钟热度。 创新的功能,精确的算法,舒适的体验都是社交产品的成功因素,然而近年来这类成功产品不多。

  • 社区产品

社区内容商业价值高:不难理解,高价值的内容对应高价值的用户需求,从而能够顺畅的衔接商业模式。例如购物讨论社区,可以迅速的结合电商模式变现。

社区内容占用用户时间长: 产品虽然现在没有很好的商业模式,但由于其占用较长的用户时间,就可以在广告的变现能力之上挖掘更多商业价值。例如专业知识社区,可以引发用户深度的思考和讨论;例如游戏二次元,搞笑娱乐的视频社区,也占用大片的休息空闲时段。

医疗

2015 年医疗行业继续是投资机构的重点关注领域,预计总融资金额将显著超出 2014 年。

根据 CVsource 统计,医疗行业各细分领域有如下的变化:

  • 医药/生物技术行业:已披露的前 11 月融资金额超出 2014 年的 40% 以上。百济神州,信达生物,歌礼生物等明星创新药企业的融资吸引了众多投资人的眼球。SFDA 今年密集出台的一系列政策对创新型医药和医疗器械企业带来了重大利好,伴随着国内资本市场多层次的体系建立,退出渠道增多,一些 PE 机构也开始在创新药领域布局,我们预计未来几年内创新药将是生物医药行业的投资主线。

image13.png

  • 医疗器械领域:2015 年前 11 月私募市场相比 2014 年呈现交易总额上升,交易数目下降趋势。主要是由于境内投资热度下降,境外投资热度上升并出现了大额境外融资。IVD (体外诊断产品)和高值耗材成为投资者的关注重点 。
  • 医疗服务领域:2015 年前 11 月披露的投资案例数和投资金额相比 2014 年均有大幅的增长,医改增加了机构对医疗服务领域的投资热情。在兼并收购方面,投资金额涨幅和平均单笔并购规模均创历史新高,并购成为企业快速发展的捷径。

image15.png

展望未来的三到五年,面对医保控费、招标降价、医药行业销售增长持续放缓的情况下,创新是中国医药企业实现「突围」的必经之路。同时企业开始走国际化路线,海外收购或引进新产品新技术,和跨国药企合作研发将持续。医疗器械行业里国产代替进口的趋势将更进一步,行业整合会更加活跃,境外收购和入境收购都有可能增加,市场份额将向拥有渠道优势的企业集中。医疗服务行业越来越被视作未来消费的增长热点,我们预计 专科连锁、综合医院改制、医药器械产业链延伸和医院集团化将是医疗服务机构的四大发展方向。

资本市场

2015 年,随着实体经济持续走下坡路,资本出现明显的溢出效应。与之对应的是上半年股市的高歌猛进,接着泡沫被管理住,资金又基本涌向了一级市场和新三板。整个资本市场我们可以看到很多变化:

  • 国内新经济资产标的供不应求,加之国内外估值体系的差距,引发美元新经济资产全面回归 A 股市场。中概股下市借壳解红筹,八仙过海,纷纷抢滩。这意味着新经济资产海外上市的年代基本结束,而且很难逆转。
  • 在新经济创富的神话之下,各类金融机构的理财产品如雨后春笋般涌现, 大量民间资金涌入,风投不再是精英的游戏,全民 VC 的时代到来。

境内资本市场

2015 年的 A 股,用「过山车」来形容再好不过。

  • 从政策层面来看,注册制、战略新兴板等涉及多层次资本市场体系建设、市场基础制度完善的改革取得突破,并将对 A 股一级市场及二级市场的未来产生深远的影响。
  • 从二级市场来看,上半年高歌猛进,下半年信心涣散反弹乏力, 二级市场戏剧性的波动也对一级市场估值和投资产生了重大影响,但由于传导的滞后性和一级市场的机构特性,一级市场波动有限,投资人并未受到较大影响,对未来的投资信心和意愿较强。
  • 从资金层面看, 国内流动性充裕,对安全资产和优质资产的配置需求强烈,尤其是经历了 2015 年的加杠杆去杠杆的市场教训之后,投资者对优质资产的配置更加渴求,形成了 A 股优秀上市公司的「资产荒」。

在上述政策供给侧的利好推动下,以及考虑到 A 股相对较高的估值,诸多优质的互联网新经济企业开始准备和筹划在 A 股上市,这将一定程度上满足国内一级市场和二级市场充裕流动性的资产配置需求,缓解国内资本市场的优质资产「资产荒」。

展望 2016 年乃至未来的趋势走向,我们也可以预见几点:

  • 美元私募市场泡沫日益严重,大量独角兽公司在私募市场将很难再进行高价融资。
  • 实体经济将可能继续处于低迷状态,使得充裕的流动性涌向新经济,A 股上市公司继续积极收购新经济资产,人民币风险投资市场估值和融资量都创新高。
  • 最好结果:中国风险投资行业进入工业化时代,成为世界第一;以传统经济为主力的 A 股市场通过并购,加之创新板新三板的成功,完成向新经济的华丽转型。
  • 最坏结果:一二级市场可能产生巨大资产泡沫,随着资金面转向紧张,泡沫将有爆破的风险,风险投资产业可能受到重创。

Postgre的常用系统表

$
0
0

查询数据库列表:

select * from pg_database WHERE datistemplate = false;

 

查询组合类型

 select * from pg_type where typtype = 'c' and typarray > 0 

AND typname NOT IN (SELECT TABLE_NAME FROM information_schema.tables)

order by typname 

 

根据名称查询OID:

select 'testdbschema1.t1'::regclass::oid

 

根据OID查询名称:

select 16392::regclass

 

查询所有表

select * from information_schema.tables where  table_Catalog = 'testdb1' and table_schema='testdbschema1'

 

Domain:

可以基于某个基本数据类型,定义一个domain,并在这个domain上定义一个或多个check,举例:

N个表都有一个邮政编码字段,为了防止用户输入非法的邮政编码,我们需要在这个字段上定义一个check来验证用户的输入数据,显然,如果有100个表有这个字段,那么我需要定义100次这个验证规则,而且一旦规则发生变化,又需要做100次的修改

正确的做法是,定义一个domain,该domain上定义这个check,然后这100个表的邮政编码字段,都使用这个domain作为其数据类型即可:

 

CREATE DOMAIN testdbschema1.us_postal_code

  AS text

  COLLATE pg_catalog."default"

  DEFAULT '000000'::text

  CONSTRAINT c1 CHECK (VALUE ~ '^\d{5}$'::text OR VALUE ~ '^\d{5}-\d{4}$'::text)

  CONSTRAINT c2 CHECK (VALUE IS NOT NULL);

ALTER DOMAIN testdbschema1.us_postal_code

  OWNER TO testdbrole1;

COMMENT ON DOMAIN testdbschema1.us_postal_code

  IS '测试domain1';

 

domain的default默认值:如果在列上定义了default,则覆盖domain上定义的default值,同样,如果在domain上定义了默认值,则覆盖其基础类型的默认值

 

查询domain列表:

select * from information_schema.domains;

查询domain的OID、OWBER、默认值:

select oid,* from pg_type where typname='us_postal_code' and typtype='d' 

查询domain的备注:

select * from pg_description where objoid = 24605

查询domain的check:

select * from information_schema.domain_constraints where domain_schema = 'testdbschema1' and domain_name = 'us_postal_code'

select * from information_schema.check_constraints where constraint_schema='testdbschema1' and constraint_name = 'c1'

 

查询表的所有列

 select table_catalog,table_schema,table_name,column_name,ordinal_position,column_default,

 is_nullable,data_type,character_maximum_length,character_octet_length,

 numeric_precision,numeric_precision_radix,numeric_scale,datetime_precision,interval_type,

 interval_precision,collation_catalog,collation_schema,

 collation_name,domain_catalog,domain_schema,domain_name,udt_catalog,udt_schema,udt_name,dtd_identifier,

 is_updatable     from information_schema.Columns where table_name = 't1'

注意,列的数据类型为数组时,部分数据类型,不是存放在data_type字段中,而是存在在 udt_name字段中,然后某些类型,还需要通过

 

select * from information_schema.element_types where object_name = 't2' or object_name = 't1' ;

查询出其显示的字面类型,比如 "_timestamp" -->"timestamp without time zone"

 

查询所有可用的数据类型:

系统原生态的那些类型+自定义符合类型(前面已写如何获取)+domain(前面已写如何获取)

 

查询表上的约束

select * from information_schema.table_constraints

 

查询表上的索引:

SELECT i.relname as indname,

       i.relowner as indowner,

       idx.indrelid::regclass,

       am.amname as indam,

       idx.indkey,

       ARRAY(

       SELECT pg_get_indexdef(idx.indexrelid, k + 1, true)

       FROM generate_subscripts(idx.indkey, 1) as k

       ORDER BY k

       ) as indkey_names,

       idx.indexprs IS NOT NULL as indexprs,

       idx.indpred IS NOT NULL as indpred

FROM   pg_index as idx

JOIN   pg_class as i

ON     i.oid = idx.indexrelid

JOIN   pg_am as am

ON     i.relam = am.oid

where idx.indrelid::regclass = 'testdbschema1.t1'::regclass;

 

 



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


ITeye推荐



多种支付渠道路由方案有哪些?

$
0
0
这里简单说一下第三方支付在做支付渠道路由设计的一些思路,供参考。作为商户,接入多家第三方支付,在渠道路由策略上比第三方支付的简单多。

1、支付渠道的封装层次
一般分为:支付接口->支付通道->支付渠道->支付产品->支付解决方案
支付接口指的是银行等提供的技术接口。
支付通道是对支付接口的封装,并包含了诸如具体合作银行及通道的详细信息。例如同为某家商业银行的某个支付接口,非总对总的情况,支付公司可能同时在北京分行、上海分行接入。
支付渠道是对支付通道的业务封装,包含了诸如通道成本、最低商户费率等信息。
支付产品是第三方支付对外提供的产品,例如快捷支付。
支付解决方案是针对某个行业的整体解决方案,包含了多个支付及行业定制需求。

所谓的支付渠道路由在以上的几个封装层次上都可以发生,因此以下指的“支付渠道路由”的概念是泛指,可能涉及以上各层次。

2、支付渠道路由的设计
一般采用规则引擎或类似方案(例如基于groovy),以支持对规则集灵活调整。

一个相对丑陋的支付渠道路由的设计方案(不一定很合理,仅供参考)


3、支付渠道路由的一些例子
按费率。
按业务级别。
按业务类型。
按渠道交易总额、单笔交易额、渠道限额等额度信息。
按支付渠道类型:移动支付,在线,代扣,b2b,信用卡无磁无密,游戏点卡等。
按支付渠道可靠性要求,例如支付成功率。
按商户类型。
按渠道状态,例如监控系统发现某渠道掉单率较高时候。
按照到账时效。
按所在银行账户的资金头寸。
按营销策略,例如某个渠道年底有营销活动。
按支付渠道优先级,可以是静态优先级,也可以是动态优先级,实际上优先级的也概念包含了以上各种路由规则。

其实支付渠道路由并没那么高大上,如果单纯只是满足企业当前的业务需要,用最丑陋的If-Else方式也能搞定。最复杂的问题是怎样让支付渠道路由的架构设计能够快速响应业务快速发展、业务模式创新的需要。

来源:知乎 www.zhihu.com
作者: 梁川

【知乎日报】千万用户的选择,做朋友圈里的新鲜事分享大牛。 点击下载

此问题还有 1 个回答,查看全部。

[观点]维基百科的流行导致了它的衰落

$
0
0

维基百科难以吸引新的志愿编辑,这已是一个众所周知的现象,而对新人不友好的社区管理人员以及资深编辑被认为与此相关。明尼苏达大学、加州伯克利和华盛顿大学的研究人员发表的 论文(PDF), 只是再一次证明了这一观点。 研究人员称,像维基百科这样的开放协作系统需要维持一个庞大的志愿贡献者池,需要不断的补充新人,需要允许部分新人从社区的边缘逐渐进入到中心。

在这方面维基百科早年做的很成功,但从2007年开始情况发生了改变,志愿者持续下降。一种解释是维基百科的条目内容接近完整,不需要 多少补充了,但研究显示维基百科最受欢迎的文章质量仍然很差。

研究人员认为是因应快速增长而引入的质量管理方式改变导致了这种现象:质量控制机制的限制和 拒绝内容贡献的算法工具是导致新人流失的主要因素。这些限制僵化的反对改变,尤其是新贡献者递交的改变。                  

Viewing all 11804 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>