scourgen

9四/110

2011北京QCon全球企业开发大会演讲点评-day2

昨天晚上在二楼和和盛大的Hax小聊了一会HTML5发展,然后除了门儿去东四吃卤煮火烧,车费花了小一百,卤煮一碗才19,回来的时候的哥夸我真棒找对了地方,东四的那家卤煮是老北京公认的老店,的哥还夸我说晚上肚子饿出来吃卤煮,这才叫做生活⋯⋯

废话不多说,今天的大会照样是非常精彩,早上第一场是来自Spring的Java云计算的主题,从Juergen的演讲中提到了一些Spring的特性,例如Cache,Servlet支持,将来不再会有web.xml这种配置文件等等,没有给我留下特别深的印象,可能也是因为Java社区在javaee方面的发展已经趋于稳定,在javaee没有大的版本变更和新技术出现的情况下很难有技术上的突破和变化,Jar Hell虽然很让人头疼,但是大家都已经这么疼过来了,这时候再改不改也无所谓了。

第二场是由百度的吴波所演讲的离线计算集群整合主题,吴波提到了目前几个较大的离线运算库,例如知名的SETI@Home,想当年我也为了SETI上的排名做过一些不太安分的事情⋯⋯吴波提到了在业务量发生巨大增长的时候,如何用其分布式任务消息中心去管理数以万记的服务器运算,如何在数据事实性有要求的情况下实施对系统负载做监控,甚至做到任务权重再分配以减轻特定服务器的压力。吴波说得非常好,但分布式离线计算这个话题对于在座的很多公司都只具有参考意义,对于以整个互联网为样本的数据业务分析和处理也只有搜索引擎会去干这种事情了。吴波也提到了在不断提高的数据面前计算能力也需要跟进,是不是可以考虑一下对于事实性不那么高的任务在百度内部采用SETI@home的方式去处理呢?以百度6000个员工,每个员工1台普通i5电脑提供50GFLPS,每天运算3个小时来算,每天也可以提供近4万的GFLOPS了,快赶上三分之一台Blue Gene了。

第三场是Netflix的Adrian提供的基于云计算架构的主题,演讲中Adrian提到了Netflix已经实现了100%的云端化,他们的云提供商是Amazon,主要原因是Amazon提供了许多基于云计算的组件,例如数据库,CDN,队列系统,邮件等等,从而可以让做视频的Netflix减少许多服务器升级,配置,更新,维护的工作,大家都知道视频公司对服务器数量的要求可是很高的。通过云端化,Netflix才可以将公司的重心放在业务和关键逻辑上,在服务器运位和技术支持上则可以和所有使用Amazon的公司互相共享,从另一个侧面降低了公司对于技术变更以及升级所带来的风险。Netflix在需求扩张时,可以简单的通过点几下鼠标达到迅速部署上百台服务器的目的,Amazon帮他们搞定一切。

Amazon的云计算也不是便宜的东西,Netflix虽然是美国正版视频的老大哥,也没到钱多的没地方用的地步,也会在流量节约上做很多的处理,例如将视频分片成10秒的片段,防止用户预加载视频过多但又没看完导致流量浪费,在会后与Adrian的交流中也提到了Netflix使用不同的三个CDN(Akamai,limelight,Level3)的原因是不同的CDN服务商在美国不同的区域所能提供的速度和价格是不同的,例如Netflix所在的加州,使用Level3的性价比就会比较高,看来美国老大哥和中国人有相同的跨ISP传输效率问题,这个问题还非常严重,换CCTV的说法就是美国人民生活在水生火热之中。

会后的与Adrian的交流中也了解到在数据分析界非常有名的Netflix公司的推荐算法改进大奖的一些消息和情况,数据分析领域也是随着在线交易渐渐火起来的一个技术方向,下次QCon举办方是否可以考虑添加数据分析专题?

中午的饭就那样,我昨天中午是在西餐厅吃的,今天去了中餐厅,发现东西都差不多。唯一可以表扬的是今天的果汁换成了橙汁,假冒菠萝汁被换下了,不知道是日常调换还是真的听取了我昨天的意见⋯⋯

下午我参加的第一场是由新浪带来的《面向开发的MySQL性能优化》。新浪数据库架构经历了三个变化,通过MySQL+Memcached到MySQL UDF再回到MySQL Memcached Redis的结构,可以说是非常纠结。在第二阶段新浪想通过UDF和triger去完成清除数据cache的功能,但是最终发现UDF和triger的综合性能会是一个很大的问题,其实新浪在第二阶段离Facebook的改SQL规则的方案只有一步之遥,不过这也体现了新浪数据库团队和淘宝数据库团队不同的地方,我的感觉是新浪数据库团队更倾向于scale-out,例如通过数据集群达到高并发流量的支撑,通过横向分割数据达到大规模数据存储等等,而淘宝的团队更偏向scale-up,淘宝解决问题的思路是最大化的挖掘单机性能。两家都不差钱的公司做事的方式截然不同,很明显的体现出各自技术团队的特点。

杨海朝提到的什么ip用int存,怎么用index,timestamp怎么用,prepared statement,handler socket,insert on duplicate key/replace,如何从业务上减少mysql查询等等我就不提了,点到为止,大家自己查阅《MySQL High Performance》和MySQL Performance Blog,内容都有而且更加详细,毕竟也不是什么新问题了,设计和开发的时候照着去做就行。

在这里我倒是想重点谈谈新浪团队在数据库分表时候出现的重复迁移问题,新浪每次迁移都会遇到数据reload的问题,也就是每次增加集群内数据库实例的数量时,都会遇到数据需要根据新的规则在不同的数据库中做迁移,实例一多这个活儿是能累死人的。通过hash range lookup 中间层等等几个方案实施下来最终效果也不是很好:hash没有规则,range的话数据量就固定了,lookup消耗大,就算用中间层的话其实还是得有个分片逻辑的,相应时间又会增加,总之就是麻烦事儿。我倒是曾经在为某项目做系统扩容方案的时候研究过数据转移率的问题,知道了有多少数据会被转移,多少数据会保留在原有的实例中,就可以系统的评估转移带来的cache丢失现象持续的时间和所需要的资源,毕竟在麻烦不能避免的话,那只能提早做准备。

用当时项目中所用的是取余平均分布,所以例如从4个实例升级到5个实例的过程中,升级前和升级后数据的分布是这样的:

红色标出的这些数据是在迁移过程中不需要被更改位置的,而红色之外的数据都由于数据分片的方式发生了变化,需要被转移。在这个例子中只有20%的数据还在原有的数据库。而这个计算升级到指定实例数量的数据保留率则可以很简单的通过一个excel表格计算出来,例如3个实例升级到n个实例的过程中数据的保留率如下:

第二场则是由蒋江伟带来的前台优化实践专题。淘宝前台可以理解为一般网站架构中的app层,提供主要的数据读取,页面渲染等面向用户的操作。淘宝的前台是基于java的,蒋江伟向我们展示了如何最优化调整应用所开启的线程数以达到提高QPS的效果,线程数计算方式为:线程总时间/瓶颈资源占用时间×瓶颈资源并行数,而QPS则为1000/瓶颈资源时间×瓶颈资源并行数。淘宝前端使用的模版引擎是velocity,蒋江伟也分享了他通过修改velocity的页面渲染方式,使velocity输出的页面代码从char转换为byte从而提高了100%的页面输出效率,又通过将解释执行改成了编译后执行提高了10%的效率,经过这些优化,最终对QPS的提高大概是50%左右。而在jvm执行环境方面,蒋江伟通过演示给出了合理提高jvm的young区从而提高大页面执行效率的建议。

蒋江伟带来的这个优化主题对使用java的互联网企业很具有参考性,实施起来也不复杂,能够真正帮助大家解决问题,我个人认为是今天的亮点主题。

第三场则是由艺龙的贾志峰所带来的艺龙网架构分析。艺龙网对技术的主要关注方向是解决复杂业务所带来的紧耦合性、异步化和运维上的监控。紧耦合性这个问题不仅仅出现在旅游网站中,对于所有的快速发展中的IT公司,都存在着业务逻辑不断地变复杂,原有结构无法做到很好的适应性,需要不断地修改代码以符合新的需求,而这个过程是由于其不可中断性,是非常痛苦的,引用吴波的话就是“在飞驰的汽车上换轮子”,而艺龙给出的解决方案则是SOA和中心化。艺龙通过将所有服务的配置文件做成能够动态获取和分发最新版本的方式做到了服务器的集群化管理,而在业务流转中则使用了自己开发的业务总线,业务和业务之间不直接交互,而是采取通过ESB进行分发和流转的方式进行动态的交互,减少了由于业务逻辑复杂性而产生的问题。而在介绍如何与航信系统进行交互的过程中,贾志峰也介绍了艺龙如何通过动态调整航信反馈信息的缓存有效期达到减少与航信产生数据通信的成本。艺龙对订单成功率的监控系统也较为有亮点。

总而言之,我认为电子商务领域中的旅行/票务行业面临着众多的挑战,他们在需要继承传统业务模式的基础上实现电子化和信息化,与此同时还要在保证线上业务不中断的同时做到灵活调整,艺龙的架构对电子商务网站来说具有参考性。

我参加的最后一个主题是由谢廷宝带来的《网游服务器性能优化》,在性能监控方面他介绍了通过使用机器人对游戏过程进行模拟,通过这个过程中的数据记录,分析影响用户的各个游戏环节的方案感觉很有特色,难道第一个做外挂的公司真的就是游戏公司自己?在碰到玩家好友数量过多,或者玩家间的私信太多等等技术问题上,谢廷宝给出的解决方案与SNS界基本相同。这次演讲总体上比较催眠,毕竟游戏也是一个网络应用,很多问题和处理办法与网站开发都相似,没有太多的东西可讲。我其实感兴趣的是如何保障游戏内交易过程这个问题。

最后照例插一个小广告吧,虎扑中国(hoopchina.com)是中国排名第一的体育综合门户网站,目前正在招聘PHP开发工程师,MySQL DBA这两个职位,工作地点在上海,有意者请发简历至:hr_engineer@hoopchina.com,谢谢

分类: IT 没有评论
8四/116

2011北京QCon全球企业开发大会演讲点评-day1

早上是三场专题演讲,分别是Facebook的《支撑Facebook消息处理的HBase存储系统》,Oracle的《Java EE 7平台:走进云计算》以及《在实践中实现企业的敏捷性

Facebook的Nicolas在演讲时演示了在中国打开Facebook.com是什么样的,当然结果是引得大家大笑,不过这也引起了一个引人深思的问题,那就是许多与会者会由于墙的原因根本无法访问这个全球最大的SNS网站,即使通过某些手段上了Facebook,也没有条件在Facebook中添加足够多的现实中的朋友,形成关系链,以至于体会不了Facebook中的几个特别强大的功能及其优势,例如Facebook的Messaging System,Face Recognition等。而在这种情况下,从使用者的角度会让人感觉到Facebook.com“也不过如此”,从而导致对Facebook的印象没有像校内,开心那么好。其实从我的角度来说,由于在以前的工作中认识了很多外国的同事和朋友,所以我也算是一个中度的Facebook使用者,对其技术以及一些新的功能还是深有体会的。

就拿本次Nicolas所演讲的HBase系统来说,Facebook使用其作为Messaging System的主要载体,每天数据存储量能够达到几十亿条,而HBase在Facebook的应用中也覆盖了包括Cache,数据分析,数据存储这三个不同的领域,有Facebook这样的老大哥带头,无疑是给我们中国的这些社交网站指出了一条技术上的发展方向,也显示出了Facebook技术团队与我们与会的许多中国网站包括虎扑网所不同的地方。当百姓网、新浪微博、淘宝等兄弟还在研究在纠结怎么优化MySQL性能的时候,国外的SNS抗巴子脸书哥儿早调转枪头了。

上午第二个专题演讲则是由Oracle的Lee Chuk Munn所带来的Javaee 7介绍,我在两年前用javaee开发过CRM和电子商城系统,回忆当时,在做开发和部署时总是会遇到包不兼容的问题,当时业界也没有很好的解决方案,索性大家最后都养成了自带专用jar包的习惯,也算是曲线克服了这个问题。而在这次关于javaee7的演讲中则着重介绍了javaee7的包管理功能,在包管理特性的演示中甚至出现了把jar包打包成一个deb/msi的官方打包工具,在其他特性上,javaee7也将会支持例如json,NIO v2,HTML5的websocket等功能。虽然看着打Oracle牌子的Java不太习惯,不过不得不承认被Oracle吃了的Sun并没有因为并购而停止脚步,反而种种迹象表明Java将会更加拥抱社区。

上午第三个专题演讲则是David为我们带来的在企业中实施敏捷的一些经验,我查阅过David的资料,也通过演讲了解到他在敏捷领域的丰富经验。他为我们带来的演讲也是非常精彩,David谈到了在企业实施敏捷的过程中不应该去遵循一个“流程”,而是应该根据每个团队自身的特点去实施不同的流程,Scrum Master的目标也是用每个团队成员都能理解的方式去引导大家往一个正确的目标前进,而不是提出一些高深的没人明白的规则让团队去执行。反观我这几年实施敏捷的经验,以前也往往遇到在实施敏捷几个月后,发现团队会有往听从命令做事这个方向上靠拢的倾向,而不会再去做自我改进和improve,以至于丢失了“我们=团队”这个最基本的概念。虎扑目前还在开发人员扩张的阶段,将来如果要实施敏捷我相信会是一个比较顺利的过程,毕竟有那么多经验和极具团队精神的开发团队在这里,而且不得不赞叹一下,虎扑的团队很团结也很有活力,怪不得外人会评论我们虎扑说“做体育的心肠都不坏”。

中午吃饭人很多,抱怨一下,京仪大酒店是 4星还是5星的酒店?档次应该不低了,午餐提供的果汁竟然是用糖浆和果位剂调出来的,完全没水果,全是色素和甜味剂,各位尽量少吃。

吃完回房间充个电上个网,然后下楼继续参加下午的会议,由于下午的知名网站案例分会场比较吸引人,所以我下午就一直在大会场听这些案例,错过了其他精彩的演讲,各位看看有没有其他人分享这些内容吧。

下午第一场是由百姓网的潘晓良所演讲的《为速度而生——百姓网如何优化网速》,对于能认为“速度是网站最重要的功能之一”的百姓网来说,百姓甚至撤下了Google的广告条,在百姓网通过优化网站速度从而提高用户体验这点上我是很佩服的。可是需要从一个更高角度去看待这个问题的时候,我不禁地想问:真的需要为了速度把广告都撤下么?毕竟网站收入很大的一块在于广告收入,而且google的广告也会针对百姓网这种类型的网站匹配出适合用户的内容,也不全是垃圾广告和“高朋网”吧,适当的放一些广告,为用户提供合适的站外信息来源,对于用户来说也是有利的啊?这种自我断臂的举措换取速度上的提升是否有些偏执了?

而潘先生在提到百姓的监控系统时,例举了百姓网正在使用的监控方案,不过很可惜的是百姓网至今还在使用Google Analysis这种对用户影响很大的侵入式监控方案,百姓网有没有考虑过实施基于日志的分析,从而把被ga所占用的时间还给用户?真的需要拿用户浏览器版本等js才能获取的信息的时候,也可以做抽样嘛,百姓网的用户访问量和用户基数那么大,取百分之一的样本也不至于影响总的数据。百姓网的榜样craigslist也没有用ga。顺便说一下,百姓的html代码都没有经过最小化处理,很多空格和换行是可以去掉的,这样还能节省一部分流量,虽然量不是很大。不过看在实施起来并不复杂的角度上,潘先生还是可以考虑一下的,对于手机用户这些流量敏感用户来说,0.1k也是肉。

潘先生还提到了百姓网目前遇到的一些问题,例如多机房数据不同步,数据延迟导致一致性无法保证,其实这个问题在所有采用分布式架构的互联网公司中都会碰到。为了解决网络延迟,业界有多种解决方案,例如硬件上比较有效的是在数据中心之间部署VPN加速设备,其原理是这些硬件设备会将TCP包打成UDP,然后用特殊的加密和压缩方式达到高效传输数据的目的。而软件上,则可以使用在多个机房部署消息队列的方案,数据直接走消息队列,或者数据走replication,清cache以及其他操作走消息队列两种方案,具体哪种取决于你们不同的应用和需求。当然在这点上还是facebook最牛逼,直接改了MySQL的SQL语法验证规则,把需要删除的cache的key放在sql里通过replication的同步功能直接送到节点上去。感谈一下脸书哥,你又把我们甩在了后面。

下午第二场是新浪微博的《构建高性能的微博系统——再谈新浪微博架构》,感觉杨先生此次演讲就是给redis和protobuf做广告的,一些微薄界很头疼的问题例如某些用户following太多,新浪微博竟然用业务手段给解决了:新浪微博限制了最多follow 2000人的限制。通过业务手段解决技术问题也不愧为一种很实用的解决问题的思路,相信这个解决方案在隔壁的《投资家CLUB》里应该会作为经典案例得到表扬,可这是在QCon啊,产品经理不会来的啊,被需求逼着的程序员你伤不起啊。杨先生也谈到Redis,Redis确实是个好东西,在包括虎扑在内的很多互联网公司中都已经得到了广泛的应用。之后杨先生提到了google的protobuf协议,在夸了一顿protobuf,然后举了诸如3-5k的json,转成xml要10k,转成protobuf只要500字节之类的案例之后,感觉还是有必要在虎扑内部架构之间的数据传输上推广这种新的数据格式的,让我回到虎扑后先研究一下到底有没有那么神。

下午第三场是由天涯论坛带来的技术进化史,天涯目前的架构很杂,前端是均衡和四层交换机F5,中间是Haproxy和Varnish,App用到了IIS+asp,Resion+JSP,ICE,PHP等技术提供不同的服务,后端则是Memcache和Redis为缓存,MySQL为数据仓库的数据库集群。相信天涯目前这个格局也是经过了无数批人前仆后继的不断改版,重构所导致的,技术团队也至少换了3批人。如此混乱的技术架构抛开维护性不谈,无论是开发速度还是与前后端服务的兼容性都是能折腾死人的,想想为asp,jsp,php都装上memcached支持就能让天涯的系统工程师郁闷半天(如果他们在asp,jsp,php里都用memcached的话)。而天涯技术上唯一的亮点则是其自主开发的memlink缓存服务,具体是个什么东西林先生也没透露太多,不过从名字应该可以猜出来是类似于支持链表之类的数据格式的类Redis缓存数据库吧,本来我本来还期待天涯和Google合作后会有一些技术上的亮点能够展示给我们的,可惜一点都没有,不知道是天涯和Google之间有保密协议还是⋯⋯。

最后王建科介绍了天涯将来的发展规划,提到了云,Saas,PaaS,IaaS,虚拟化,动态架构之类的,我觉得这个就太虚了,骗骗投资人钱还行,大家搞技术的看过就算了。

最后一场是淘宝给我们带来的《淘宝商品库优化实践解析》,淘宝商品库是淘宝最核心的数据库,没了商品的淘宝还能叫淘宝么?这个数据库的性能高低直接影响各位亲们做生意的心情,淘宝能不重视么。来自淘宝的余锋向我们展示了淘宝数据库团队优化MySQL的整个过程,通过从MySQL本身,到操作系统,网络,硬件等等多个方面,淘宝数据库团队将MySQL数据库的单机性能从原有的10000 QPS提高到了34000QPS,实在是太强了。

不过林先生所分享的优化案例也实在是太过于Geek和具有限制性,好像一群汽车改装狂人在研究如何改装才能将一辆摩托的速度提高到极致--最后的结果竟然是往摩托车上装喷气发动机。淘宝的优化经历很经典,对于广大MySQL DBA来说具有参考性,可惜的是对于广大互联网公司来说却并不具有操作性,毕竟不是所有公司都有像淘宝这样的极端案例可供研究,也没有这么多精力放在为了提高1000QPS而改MySQL源码这样的事情上。从优化数据库这个角度来说,包括虎扑之内的公司,倒是可以尝试去思考如何使用硬件来解决这个性能问题,极端情况就如我在演讲后提问环节中提到的Fusionio硬盘,它可以在普通MySQL服务器上提供100000的QPS,但是价格也是很吓人,具体数字请直接联系在场的fusionio代理,好像是个女的,有机会认识一下?回到正题上来,对于一般互联网公司来说,在普通情况下还是研究如何部署SSD硬盘吧,虎扑目前正在实施对数据库进行SSD硬盘升级,初步测试下来性能提升很大,价格不贵,操作起来也很简单,具备可行性,如果有机会的话可以向各位做个介绍。

最后插一个小广告吧,虎扑中国(hoopchina.com)是中国排名第一的体育综合门户网站,目前正在招聘PHP开发工程师,MySQL DBA这两个职位,工作地点在上海,有意者请发简历至:hr_engineer@hoopchina.com,谢谢

分类: IT 6 评论
25十/100

某公司笔试题目解答

一个偶然的机会,拿到了这份某互联网公司的笔试题目,抱着闲着也是闲着的态度做了一下答卷,发出来以供各位参考。

软件工程师笔试题目

1.  XX网每个信息页面下方都有一个信息被浏览次数统计的计数器,如果让你用你熟悉的代码写一个这样一个支持8位ID统计的计数器,你的思路是怎样的?会怎样写?需要用code实现。

当帖子的并发量很高时,如果用传统的count或read会对数据库造成很大的读io,而在新用户浏览过该帖子后update阅读数量时则会产生大量的write lock,所以对于这个问题我使用memcache+php的解决方案.

count.php中已经回答了问题一.作为该问题的衍生,我设想了几个可能发生的问题并且给与大概的解决方案

1.如果网站访问量成倍增长,则memcache中的数据迟早会超出内存限制,此时该如何处理?

此时有三种解决方案,前两种不需要增加服务器,第三种是从硬件角度解决问题,需要增加服务器

第一种是增加内存,扩大memcache的允许运行空间,memcache在64bit系统下最大可以使用1t的内存空间.

第二种是开启memcahce的内容压缩功能,当该功能被开启后,cpu的负荷会略微上升,而内存占用由于压缩的关系则会降低,从而起到增加系统可用空间的目的.

第三种是对数据进行分片,分片方法可以使用余数法或者hash法,最简单的例子如下:

有三台服务器,分别位A,B,C,则id为1的数据的进A,2进B,3进C,4进A,如此循环.

2.如果memcache服务器产生运行异常,memcache中的统计数据该如何保存?

有两种办法,第一种实现起来较为简单,但是有可能损失一小部分数据,第二种不会损失数据,但是会增加硬件投入.

第一种,使用crontab每隔一段时间对数据做dump,将所有数据依次存入数据库中,待问题发生时,只要将数据从数据库导入memcache数据库即可.

第二种则是使用memcache的addserver方法,将同一键值存放在多个实例中,根据服务器是否正常运行来动态的选择从哪台服务器取得数据.

3.当memcache集群的服务器数量增多时,该如何对数据进行平均分片以保证每台服务器的负载都处在平均水平?

可以采用数据分片或者hash的方法,或者使用memcache代理软件:magent

2.  XX网不允许一个人在一天之内发布过于重复或者接近重复信息,如果让你实现一个重复度检测算法判断,你的思路是怎样的?code上怎么写?需要用code实现。

我对于这个问题有几个不同的解决思路:

1.关键信息重复程度检测

对于不同的信息,它们最终地目是让浏览者产生兴趣并且联系发贴人,而在这个逻辑中,有几类信息是必不可少的,比如联系信息,包括联系人的电话(这是最重要的),email,qq号码,msn等联系方式,不管信息的结构如何变化,这个最重要的信息是不可能产生变化的,即使有变化也只是一些简单的替换,制造杂音等等,例如将手机号码加空格,换行,用中文代替阿拉伯数字等等.

而对于关键信息的提取这一问题,可能需要一个数据库来储存大量的产品基本信息,比如对于笔记本电脑分类,这个数据库可能牵涉的数据有:品牌,型号,制造年份,保修年数等等.将关键数据提取出来与现有数据做匹配,则可以判断该信息是否是重复信息.

具体代码见duplicateCheck.php内的checkDuplicateByKeyword方法.

所以判断关键信息是否重复可以用来作为判断此信息是否重复的解决方案之一.而由于单纯判断信息重复程度会带来一些问题,比如应该避免不同用户发送相同信息而被误判为重复信息的情况.所以需要第二个解决方案:判断用户是否重复.

2.信息发布来源重复程度检测

对于普通用户来说,可以通过判断IP,判断浏览器,植入cookie等方法判断这个用户在24小时内是否在网站上发送过信息.

3.信息正文重复程度检测

最后一个方法则是判断一段文字和一段文字的相似程度,相似程度是一个浮点数,从0到100,如果两端文字的相似程度达到了一个阀值(这个阀值可以通过大量的测试数据来得出,对于不同长度的文本可以采用不同的阀值,因为文字的长度越短,变动过的文字占全部文本的比例就越低),则可以判断为重复信息.

详见duplicateCheck.php内的checkDuplicateRateBySimilarText方法

附:源代码:

count.php


<?php
//define key
define("POST_ID", 12345);
define("KEY",'post_counter_'.POST_ID);

//create connection to memcache server
$memcache = new Memcache;
$memcache->pconnect('localhost', 11211) or die ("Could not connect");

/* ** IMPORTANT **
 * If we create the key when user writes a new post,then we don't need check the key is exist or not,it will save time.
 * ** IMPORTANT **/
$var = $memcache->get(KEY);

//If key is not exist,then create it.
if($var==false){
 $memcache->set(KEY,1,false,88888);
 $result=1;
//If key is exist,then increment it.
}else{
 $result = $memcache->increment(KEY, 1);
}

//print result
echo 'counter of this post:'.$result;

duplicateCheck.php


<?php

//test data1
$text_1_1 = array(
 'id'=>1,
 'title' => '',
 'category' => '',
 'location' => '',
 'price' => '',
 'description' => "移动包月卡,每月3G流量7月启用卡剩余8个月即800元可10086查询\n
中兴网卡信号好速度快,因住地已装网线留着无用转给需要的人,价可小议\n
联系方式159 00491388 (直接联系拒绝短信)"
);

//test data 2
$text_1_2 = array(
 'id'=>2,
 'title' => '',
 'category' => '',
 'location' => '',
 'price' => '',
 'description' => "移动包年卡,每月3G流量7月启用卡剩余8个月即800元可10086查询\n
中兴网卡信号好速度快,因住地已装网线留着无用转给需要的人,价可小议\n
联系方式15900491388 (直接联系拒绝短信)"
);

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////

function checkDuplicateByKeyword($text){
 $database=array(
 array(
 'category'=>'移动',
 'keywords'=>array(
 '充值卡',
 '包年卡'
 )
 )
 );

 //check category
 foreach($database as $key => $value){
 if(__IsKeywordExist($value['category'],$text['description'])){
 echo "ID:".$text['id'].'的帖子 属于{'.$value['category'].'}分类'."\r\n";
 foreach($value['keywords'] as $k2 => $v2){

 //echo $v2;
 if( __IsKeywordExist($v2,$text['description']) ){
 echo "ID:".$text['id'].'的帖子 发现重复关键信息';
 }
 }
 }else{
 }
 }
}

function __IsKeywordExist($keyword,$text){
 if(strpos($text,$keyword)===false){
 return false;
 }else{
 return true;
 }
}

/*
 * return:
 *
 * [scourgen@SMBP:~/BaiXing]$ php duplicateCheck.php
 ID:1的帖子 属于{移动}分类
 ID:2的帖子 属于{移动}分类
 ID:2的帖子 发现重复关键信息
 */

checkDuplicateByKeyword($text_1_1);
checkDuplicateByKeyword($text_1_2);

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

function checkDuplicateByUser($text_1){

}

function checkDuplicateRateBySimilarText($text_1,$text_2){
 similar_text($text_1, $text_2,$p);
 return $p;
}

//return 98.5324947589
echo checkDuplicateRateBySimilarText($text_1_1['description'], $text_1_2['description']);
分类: php 没有评论
7二/100

解决UCenter在添加应用时出现”通信失败”的问题

最近在研究UCenter,研究过程中碰到一个非常奇怪的问题,那就是添加完一个应用后,无法正常的通信,老是出现通信失败的问题.

经过跟踪,发现竟然是uc.php内的一个变量没有设置,导致uc.php在处理通信请求时总是失败

if(in_array($get['action'], array('test', 'deleteuser', 'renameuser', 'gettag', 'synlogin', 'synlogout', 'updatepw', 'updatebadwords', 'updatehosts', 'updateapps', 'updateclient', 'updatecredit', 'getcreditsettings', 'updatecreditsettings'))) {
 require_once DISCUZ_ROOT.'./include/db_'.$database.'.class.php';
 $GLOBALS['db'] = new dbstuff;
 $GLOBALS['db']->connect($dbhost, $dbuser, $dbpw, $dbname, $pconnect, true, $dbcharset);
 $GLOBALS['tablepre'] = $tablepre;
 unset($dbhost, $dbuser, $dbpw, $dbname, $pconnect);
 $uc_note = new uc_note();
 exit($uc_note->$get['action']($get, $post));
 } else {
 exit(API_RETURN_FAILED);

}

第58行的$database竟然在前文没有定义过,改成'mysql'后,就可以正常通信了.

分类: IT 没有评论
24一/100

Firefox 3.6 性能测试,较Firefox 3.5 性能提高47%!

Firefox 3.6终于发布了,官方发布的Features集中在了宣传新的Personas换肤功能上.其实Personas在去年就开始在Mozilla Addons下载中心提供测试及下载了,Scourgen周围的很多Firefox使用者都用这个插件换了主题.可惜Personas还不支持换标题栏里更换背景图片,只能给标题栏换一个颜色.

而其实3.6最大的改进则提供了HTML5以及极大的增强了JavaScript的性能,而对此官方却没有做太大的介绍,只放了一个演示视频做对比,Scourgen花了点时间对Firefox3.6的JavaScript性能较上一版本(Firefox 3.5.7)做了一个对比,可以发现多数项目都有100%左右的提高,而平均性能提高则达到了47%

分类: IT 继续阅读
22一/103

最新的Adium 1.4hg修改版,支持小i的msn群里显示发言人名字.

Adium不能在小i的msn群里显示发言人的名字,用/showname也没有用,逼得我开着虚拟机用Windows live messenger.

今天看到一篇文章,是讲如何将Adium修改成支持msn群的,但是提供的都是老版本,于是下载了Adium的源码,一步一步进行修改.

  1. 安装Mercurial
    Adium使用Mercurial管理代码,所以得先装这Mercurial.个人建议用mac port进行安装,比较方便.

    sudo port install mercurial
  2. 安装完就可以创建一个工作目录,然后下载Adium的源码了:
    cd ~
    mkdir adium_build
    hg clone http://hg.adium.im/adium
  3. 下载完成后进入Utilities/dep-build-scripts目录
    cd Utilities/dep-build-scripts/
  4. 下载一些相关的包,以下脚本会自动下载10几个包,并且会自动把文件解压到source目录
    ./common.sh -d
  5. 下载Pidgin的源文件并解压缩
    cd source
    mkdir im.pidgin.adium.1-4
    cd im.pidgin.adium.1-4
    wget http://developer.pidgin.im/static/pidgin.mtn.bz2
    bzip2 -d pidgin.mtn.bz2
  6. 因为pidgin是用monotone这个源码管理软件进行管理的,所以我们得再安装monotone
    sudo port install monotone
  7. 然后对monotone的独特项目管理包(.mnt)文件进行解压,得到pidgin的源文件
    mtn db -d pidgin.mtn migrate
    mtn -d pidgin.mtn pull --set-default
    mtn.pidgin.im "im.pidgin.*"
    mtn -d pidgin.mtn co -b im.pidgin.adium.1-4 .
  8. 用monotone更新一下pidgin的代码
    mnt pull
    mnt update
  9. 然后开始build相关联的包
    ./general_dependencies_make.sh
  10. 如果很快就结束的话,多半是有错误发生,可以看一下log文件,比如我就出现了perl里的某个XML Parser包找不到的错误,导致intltool包编译不成功.
    vim ./build/purple_dep_make.log/usr/bin/install -c -m 644 'libgadu.pc' '/Users/scourgen/StudyWorkSpaces/Adium/adium-1.4/Utilities/dep-build-scripts/build/root-i386/lib/pkgconfig/libgadu.pc'
    make[2]: Nothing to be done for `install-exec-am'.
    make[2]: Nothing to be done for `install-data-am'.
    checking for a BSD-compatible install... /usr/bin/install -c
    checking whether build environment is sane... yes
    checking for a thread-safe mkdir -p... /Users/scourgen/StudyWorkSpaces/Adium/adium-1.4/Utilities/dep-build-scripts/source/intltool-0.36.2/install-sh -c -d
    checking for gawk... gawk
    checking whether make sets $(MAKE)... yes
    checking for perl... /opt/local/bin/perl
    <span style="color: #ff0000;">checking for XML::Parser... configure: error: XML::Parser perl module is required for intltool</span>
  11. 于是再调用port安装这个XML Parser
    sudo port install p5-xml-parser
    --->  Computing dependencies for p5-xml-parser
    --->  Fetching p5-xml-parser
    --->  Attempting to fetch XML-Parser-2.36.tar.gz from http://distfiles.macports.org/perl5
    --->  Verifying checksum(s) for p5-xml-parser
    --->  Extracting p5-xml-parser
    --->  Configuring p5-xml-parser
    --->  Building p5-xml-parser
    --->  Staging p5-xml-parser into destroot
    --->  Installing p5-xml-parser @2.36_0
    --->  Activating p5-xml-parser @2.36_0
    --->  Cleaning p5-xml-parser
  12. 再执行第9步,正常的话应该得到如下提示:
    Done - now run ./purple_dependencies_make.sh
  13. 然后开始编译purple的相关包,这步时间会稍微久一点.
    ./purple_dependencies_make.sh
  14. 然后在正式编译purple之前进行修改,加入显示msn群里发言人名字的功能.
    if ((value = msn_message_get_attr(msg, "P4-Context")) != NULL)
    {
    char *body_enc2;
    body_enc2 = g_strdup_printf("<b>***%s***</b>  %s", value,
    body_enc ? body_enc : "");
    g_free(body_enc);
    body_enc = body_enc2;
    }

    将上述代码插入到source/im.pidgin.adium.1-4/libpurple/protocols/msn/msg.c 847行之后,变成:

    842 #if 0
    843         if ((value = msn_message_get_attr(msg, "User-Agent")) != NULL)
    844         {
    845                 purple_debug_misc("msn", "User-Agent = '%s'\n", value);
    846         }
    847 #endif
    848
    849     if ((value = msn_message_get_attr(msg, "P4-Context")) != NULL)
    850     {
    851         char *body_enc2;
    852         body_enc2 = g_strdup_printf("<b>***%s***</b>  %s", value,
    853             body_enc ? body_enc : "");
    854         g_free(body_enc);
    855         body_enc = body_enc2;
    856     }
  15. 然后开始编译LibPurple
    ./purple_make.sh --i386 --regenerate
  16. 然后编译Mac通用的二进制文件
    ./universalize.sh
  17. 然后编译多语言文件
    ./make_po_files.sh
  18. 最后安装新的Frameworks到Adium中
    ./copy_frameworkds.sh
  19. 最后回到Adium的主目录,进行编译
    cd ../..
    make
  20. 完成后,会在主目录的build/Release-Debug目录中出现Adium.app,这就是最终的可执行文件了.
    打开程序,看看效果.

    不错吧,已经可以看到3个*中间的发言人名字了.

为了方便大家,这里提供我编译的版本的下载地址,是基于最新的1.4hg进行修改的,直接下载就能用了

Adium 1.4hg Scourgen编译版

分类: IT 3 评论
21一/100

用Python脚本抓取Linkedin中的公司信息

Linkedin是一个在国外比较知名的商务型SNS.最近在研究Linkedin时,发现Linkedin在添加个人信息时的公司名称提示功能很强大,通过这个功能几乎可以获取一份大型公司名录.于是用Python花了几分钟写了一个小脚本,顺利的获取到了6000余条公司信息.

代码如下:

import urllib2
import json
import MySQLdb

db = MySQLdb.connect(host="localhost",unix_socket='/Applications/MAMP/tmp/mysql/mysql.sock',port=3306,user="root",passwd="000000",db="linkedin_spider")
db.set_character_set("utf8")

def getData(str):
 req = urllib2.Request(
 url = 'http://www.linkedin.com/typeaheadv3/company?query='+str+'&loc=P'
 )
 result = urllib2.urlopen(req).read()
 b= json.JSONDecoder().decode(result)
 for k in b["resultList"]:

 cursor = db.cursor()
 if k.has_key("imageUrl"):
 sql = u"insert into companys values(null,\""+k['displayName'].replace('"','\\"')+"\",\""+k['subLine'].replace('"','\\"')+"\",\""+k["headLine"].replace('"','\\"')+"\",\""+k['imageUrl']+"\",\""+k['url']+"\",\""+k['id']+"\")"
 else:
 sql = u"insert into companys values(null,\""+k['displayName'].replace('"','\\"')+"\",\""+k['subLine'].replace('"','\\"')+"\",\""+k["headLine"].replace('"','\\"')+"\",\"null\",\""+k['url']+"\",\""+k['id']+"\")"
 print sql
 cursor.execute(unicode(sql))
 print k['displayName']

a="abcdefghijklmnopqrstuvwxyz"
i=0
for x in a:
for y in a:
 print i
 i=i+1
 getData(x+y)

MySQL数据库结构:

SET NAMES utf8;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
--  Table structure for `companys`
-- ----------------------------
DROP TABLE IF EXISTS `companys`;
CREATE TABLE `companys` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `displayName` varchar(500) COLLATE utf8_bin DEFAULT NULL,
 `subLine` varchar(500) COLLATE utf8_bin DEFAULT NULL,
 `headLine` varchar(500) COLLATE utf8_bin DEFAULT NULL,
 `imageUrl` varchar(500) COLLATE utf8_bin DEFAULT NULL,
 `url` varchar(500) COLLATE utf8_bin DEFAULT NULL,
 `link_id` varchar(500) COLLATE utf8_bin DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

关键字设置的很简单,从aa循环到zz,每个关键字能够搜到10条信息,所以不考虑数据重复性的话,这个程序一共能够抓取到26*26*10=6760条公司信息.而实际运行结果则是插入了6518条,而其中34条是重复数据,可见Linkedin的公司数量非常之多.

需要注意的几个问题:

  • Linkedin公司介绍中有西欧字符,默认情况下无法插入sql,报错
    Traceback (most recent call last):
     File "main.py", line 29, in <module>
     getData(x+y)
     File "main.py", line 21, in getData
     cursor.execute(sql)
     File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/MySQLdb/cursors.py", line 149, in execute
     query = query.encode(charset)
    <span style="color: #ff0000;">UnicodeEncodeError: 'latin-1' codec can't encode character u'\u0142' in position 89: ordinal not in range(256)</span>
    smbp:Linkedin_Spider scourgen$ python2.6 main.py
    /opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/MySQLdb/__init__.py:34: DeprecationWarning: the sets module is deprecated
     from sets import ImmutableSet

    解决办法是将sql字符串转换成utf8,同时也将数据库的连接属性改成utf8即可

    #设置连接属性:
    db.set_character_set("utf8")
    #u"" 代表将字符串转成unicode
    sql=u"insert ..."
    #再转一次,以防万一
    cursor.execute(unicode(sql))
    
  • 公司简介中有些数据含有引号,导致sql语句构造失败
    replace('"','\\"')可以将"替换成\",以便构造sql语句
    sql = "insert ...."+k['subLine'].replace('"','\\"')
21一/100

实测Bootcamp 3.1,显卡性能大幅度提高

Apple发布了虚拟化软件Bootcamp的3.1版本,在这个版本中,除了正式支持了Windows 7之外,最明显的改进就是极大地提高了显卡的性能。

显卡驱动升级到了188.61

而在我的MacBook Pro上的Windows 7的显卡评分也从3.0时的5.9 5.3提高到了6.4 6.4


升级前


升级后

分类: IT 没有评论
19一/101

JavaScript Templates(JST),JavaScript语言下的模板引擎

JavaScript Templates(简称JST)是TrimPath开发的一款JavaScript语言的模板引擎,它可以在任何网页的前端使用,并用来处理大量的,实时的数据的前台展示.JST也是vivipos的打印模板处理引擎.

JST使用的语言是JavaScript,而使用的数据格式则是普通的JSON格式.

简单示例:

<div id="tpl_id">Hello <b>${name}</div>
<script language="javascript" src="trimpath/template.js"></script>
<script>
var a={name:"scourgen"};
alert(TrimPath.processDOMTemplate("tpl_id", a));
</script>

则会alert出scourgen.

JST支持一下几种语法:

  • 变量判断:
     ${name|default:"is null"} 
  • 语句判断
    {if name=="scourgen"}
    scourgen is here
    {else}
    no people
    {/if}
    
  • 赋值
    {var nameList=["scourgen","John","Shelly"]} 
  • 循环
    {for name in nameList}
    Hello ${name}!
    {/for}
     
  • 宏操作
    //借用官方的例子:</li>
    </ul>
    <a name="Macro_Declarations">  Examples:
    {macro htmlList(list, optionalListType)}
    {var listType = optionalListType != null ? optionalListType : "ul"}
    <${listType}>
    {for item in list}
    <li>${item}</li>
    {/for}
    </${listType}>
    {/macro}
    
    Using the macro...
    ${htmlList([ 1, 2, 3])}
    ${htmlList([ "Purple State", "Blue State", "Red State" ], "ol")}
    {var saved = htmlList([ 100, 200, 300 ])}
    ${saved} and ${saved}</a>
  • 执行JS
    //借用官方的例子:</li>
    </ul>
    <a name="eval_blocks">  <select onchange="sel_onchange()"></select>
    {eval}
    sel_onchange = function() {
    ...Do some complicated javascript...;
    ...more js code here...;
    }
    {/eval}</a>
  • HTML属性/CSS压缩

    //借用官方的例子:
    <a name="minify_blocks"> <select onchange="{minify}
    ...Do some complicated multi-line javascript...;
    ...more js code here...;
    this.enabled = false;
    {/minify}">
    <select onchange="{minify END_OF_JS}
    ...Do some complicated multi-line javascript...;
    ...more js code here...;
    this.enabled = false;
    END_OF_JS"></a>

用JST的好处

  1. 提高性能:对于大数据量的,需要及时处理的数据操作,大可将数据的处理放到前台,减轻后台压力
  2. JST语法简单,JST的语法和Smarty,Velocity类似,如果有以上模板系统开发经验的话,可以马上上手.
  3. 增加系统扩展性,提供另外一种Model到View的途径
  4. JST速度极快
    我用官方的demo作了两个测试,数据量分别是5和1000
    数据量为5条记录时:

    数据量为1000条记录时:

    可以看到,虽然记录数量增长了200倍,而运行时间和程序堆栈执行次数却只增长了39倍和117倍,而通过对Profile进行进一步分析,可以看出大部分时间是在入口函数以及DOM操作上,足以得出结论:JST的性能是很适合对大容量的数据进行处理的.

分类: IT 1个评论
13一/101

谈谈VIVIPOS的市场定位和应用

去年开发vivipos时,Scourgen曾被公司派遣到台湾与FEC的vivipos团队共同工作过一段时间,通过短短十几天的时间,Scourgen很惊讶台湾的拼搏精神,同时也被vivipos的技术架构以及商业模式给吸引,这篇文章主要谈谈vivipos的背景以及市场定位.

vivipos是一台收银机,它的市场定位是收银机的中低端市场,主要客户群是中小型的零售商,这个用户群体可不像沃尔玛,苏宁那么阔气,它们才开了几家分店,用着老式的收银机,老板每天在多家店面内辗转,它们用传真机和excel统计销售额,人工进行补货,节约是他们共同的特征,在眼下,把每一分钱用在刀刃上.谁知道还会不会有下一波经济危机和另一个8万亿?它们在某种程度上是成功的,它们在国内零售业强大的内需中找到了一小片属于自己的市场份额,但它们的老板多半没有太多的零售经验,靠着积攒十几年的打工辛苦钱,或拿个同村乡亲们的集资,又或卖了大城市里的房子,靠着自己的勤劳和草根智慧,做起了属于他们自己的事业.

而如果入行早一点,可能做到现在有了50甚至100家分店,经过几次挣扎后管理方式终于初步转向了电子化,可能上过了系统,可能换过收银机,也可能做过几个网站,注册过中文域名也在百度上投过广告,但是效果始终不是那么美好,常想着为什么辛香汇的网站就比我火?为啥巴贝拉的毛利能达到70%?老板们后面始终跟着刚毕业的销售,享受着大学生们刚学会几天不久的马屁的同时觉得耐克,肯德基也没什么大不了,不就比我早做了几十年么.

中小零售行业市场是庞大的,毕竟沃尔玛再大也不可能在每个城乡里都开一个.而它们的增长性又是惊人地,只要给与他们适当的帮助,帮助他们解决零售的货源,分销,店面,顾客关系等几个最重要的问题后,它们会用高达3位数的年增长率百分比告诉你,老板又换了一辆奔驰.

而对与这个激动人心又充满无限增长潜力的传统行业,IT信息技术如何帮助其解决经营中的问题,帮助企业快速增长呢?

我们都知道用信息技术好,可是好在哪里,到底什么是信息技术,它具体能解决什么问题,在某一个特定的环境下到底能给老板们带来怎么样的利益,这才是中小型零售商最关心的问题.大的概念也不用说,饼也不用画,我们一五一十把事情说明白就行.

  1. IT产品的接受能力
    在这个把用破解软件当作习惯的地方,可千万别说你是卖软件的.在这儿软件不值钱.Windows 7在大街上才卖5块钱,凭什么要我付几万块的钱来买你这个根本没人用的软件?
    要不你是大型的专业软件开发公司,要不你遇上的是大型的业余凯子,不然可千万别谈什么软件.我保证他们愿意花3万元的单价买IBM的老式收银机,也不会来你这儿买你花了200个人月开发的新一代管理软件.
    那咋办?
    捆绑销售!
    vivipos的硬件成本不高,采用via 1G的CPU以及1G的内存,加上1G的CF卡作为唯一的储存器当硬盘用,加上15寸的触摸屏,整体成本想想就知道不是很高,要知道,主要成本在于开发操作系统以及应用平台的软件上了,而对于vivipos来说,它的软件平台甚至是开源的,但是这套软件只能运行在vivipos的硬件上.这属于用着开源的名义赚整体的利润,不过即使动机不纯,在相对垄断的POS机行业,6000元的售价也是极为诱人的了,要知道IBM的POS机,最便宜的可也没有下5位数的啊.
  2. 开店成本
    传统POS行业中,如果要上一套系统,可能牵涉到大大小小数个公司,有的提供硬件,有的提供操作系统,有的提供软件,有的提供实施,有的提供服务,等等等等,总之挺简单的事情总是最后搞的很复杂,什么A的硬件不兼容B的软件了,C对D的部署方式不认可,不提供保修了,等等乱七八糟一大堆问题,而没有一家公司能够站出来对这些设备和软件完全负责,往往出了不同的问题要找不同的人.而将方案总的包给某个集成商也不能往往也不能完全解决的问题,反而增加了一道中间手续.虽然出了问题时打继承商的维修电话,听筒里的mm说话的语调总是嗲得让你发不了脾气,但终究还是不能解决问题,如果有一家公司能提供所有的这些产品和服务就好了,俗话叫啥?一条龙服务!
    vivipos就采取了一家搞定的策略,一个国家就一个总代,硬件就2种,一个15寸的一个12寸的,除了屏幕不一样别的没区别,软件都是开源的,功能丰富界面美观,抱回家10分钟就能自学成才,想学Linux还能进vivipos的开发模式打几个命令小试一下伸手,软件出了问题自动截图上传服务器,再不行打个电话让支持中心远程界面操控你的界面,你机器上有什么问题他看得一清二楚.
    所以不但开店成本下降了,服务成本也下降了许多.但您千万别拿台300块的收银机和vivipos比,级别不一样,夸收银机好用的老板们根本不是目标客户.
  3. 信息化
    上设备,上系统的意义是啥?提高工作效率.
    在零售业态变化天翻地覆的今天,谁都不能保证我的那一亩三分地明天不会变成二亩六,如果你有一个好的什口,在本店内进行重新装修,扩大营业面积是一个最好的办法.
    可等等,我的设备怎么办?
    对于传统设备来说,要不就是单点独用,和其他设备老死不相往来,要不就是动则一个大系统,终端支持数千并发,却不允许终端的应用随着业务的变化而变化,比如在营业面积增大的情况下,如何通过简单的购买一台新设备却能够动态的接入旧的系统?举个简单的例子,我买了台新的收银机,能不能让它和我以前的那台共享一个打印机?能不能在钱箱满的时候通知其他终端?厨房菜做完了能不能告诉前台派个人来送餐??能不能.....IBM不老在吹什么"智能的XX",什么"应需而变"嘛?别听它瞎扯,能够解决具体问题的才是对你有用的,听IBM的话,把你卖了都不够塞它牙缝的.
    而vivipos却可以做到,它基于RoR的Scaffold理念,能够极为快速的配置出你所要的应用,而离散式的基于文件的数据库则使数据的远程即时传输成为可能,更为吸引人的则是它的网络节点概念:每一个vivipos都是一个节点,对于每一个节点,只有上级和下级的关系,对于上级节点,上传数据,对于下级节点,下发数据,如果办公室有一台vivipos,则可以将这台vivipos配置成最上级节点,不通过任何开发就可以看到下属所有节点的销售情况,及时的哟!
   下一页