
暂无个人介绍
Hadoop家族 整个Hadoop家族由以下几个子项目组成: Hadoop Common: Hadoop体系最底层的一个模块,为Hadoop各子项目提供各 种工具,如:配置文件和日志操作等。 HDFS: 是Hadoop应用程序中主要的分布式储存系统, HDFS集群包含了一个NameNode(主节点),这个节点负责管理所有文件系统的元数据及存储了真实数据的DataNode(数据节点,可以有很多)。HDFS针对海量数据所设计,所以相比传统文件系统在大批量小文件上的优化,HDFS优化的则是对小批量大型文件的访问和存储。 MapReduce: 是一个软件框架,用以轻松编写处理海量(TB级)数据的并行应用程序,以可靠和容错的方式连接大型集群中上万个节点(商用硬件)。 Hive: Apache Hive是Hadoop的一个数据仓库系统,促进了数据的综述(将结构化的数据文件映射为一张数据库表)、即席查询以及存储在Hadoop兼容系统中的大型数据集分析。Hive提供完整的SQL查询功能——HiveQL语言,同时当使用这个语言表达一个逻辑变得低效和繁琐时,HiveQL还允许传统的Map/Reduce程序员使用自己定制的Mapper和Reducer。hive类似CloudBase,基于hadoop分布式计算平台上的提供data warehouse的sql功能的一套软件。使得存储在hadoop里面的海量数据 的汇总,即席查询简单化。 Pig: Apache Pig是一个用于大型数据集分析的平台,它包含了一个用于数据分析应用的高级语言以及评估这些应用的基础设施。Pig应用的闪光特性在于它们的结构经得起大量的并行,也就是说让它们支撑起非常大的数据集。Pig的基础设施层包含了产生Map-Reduce任务的编译器。Pig的语言层当前包含了一个原生语言——Pig Latin,开发的初衷是易于编程和保证可扩展性。 Pig是SQL-like语言,是在MapReduce上构建的一种高级查询语言,把一些运算编译进MapReduce模型的Map和Reduce中,并且用户可以定义自己的功能。Yahoo网格运算部门开发的又一个克隆Google的项目Sawzall。 HBase: Apache HBase是Hadoop数据库,一个分布式、可扩展的大数据存储。它提供了大数据集上随机和实时的读/写访问,并针对了商用服务器集群上的大型表格做出优化——上百亿行,上千万列。其核心是Google Bigtable论文的开源实现,分布式列式存储。就像Bigtable利用GFS(Google File System)提供的分布式数据存储一样,它是Apache Hadoop在HDFS基础上提供的一个类Bigatable。 ZooKeeper: Zookeeper是Google的Chubby一个开源的实现。它是一个针对大型分布式系统的可靠协调系统,提供的功能包括:配置维护、名字服务、 分布式同步、组服务等。ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。 Avro: Avro是doug cutting主持的RPC项目,有点类似Google的protobuf和Facebook的thrift。avro用来做以后hadoop的RPC,使hadoop的RPC模块通信速度更快、数据结构更紧凑。 Sqoop: Sqoop是一个用来将Hadoop和关系型数据库中的数据相互转移的工具,可以将一个关系型数据库中数据导入Hadoop的HDFS中,也可以将HDFS中数据导入关系型数据库中。 Mahout: Apache Mahout是个可扩展的机器学习和数据挖掘库,当前Mahout支持主要的4个用例: 推荐挖掘:搜集用户动作并以此给用户推荐可能喜欢的事物。 聚集:收集文件并进行相关文件分组。 分类:从现有的分类文档中学习,寻找文档中的相似特征,并为无标签的文档进行正确的归类。 频繁项集挖掘:将一组项分组,并识别哪些个别项会经常一起出现。 Cassandra: Apache Cassandra是一个高性能、可线性扩展、高有效性数据库,可以运行在商用硬件或云基础设施上打造完美的任务关键性数据平台。在横跨数据中心的复制中,Cassandra同类最佳,为用户提供更低的延时以及更可靠的灾难备份。通过log-structured update、反规范化和物化视图的强支持以及强大的内置缓存,Cassandra的数据模型提供了方便的二级索引(column indexe)。 Chukwa: Apache Chukwa是个开源的数据收集系统,用以监视大型分布系统。建立于HDFS和Map/Reduce框架之上,继承了Hadoop的可扩展性和稳定性。Chukwa同样包含了一个灵活和强大的工具包,用以显示、监视和分析结果,以保证数据的使用达到最佳效果。 Ambari: Apache Ambari是一个基于web的工具,用于配置、管理和监视Apache Hadoop集群,支持Hadoop HDFS,、Hadoop MapReduce、Hive、HCatalog,、HBase、ZooKeeper、Oozie、Pig和Sqoop。Ambari同样还提供了集群状况仪表盘,比如heatmaps和查看MapReduce、Pig、Hive应用程序的能力,以友好的用户界面对它们的性能特性进行诊断。 HCatalog Apache HCatalog是Hadoop建立数据的映射表和存储管理服务,它包括: 提供一个共享模式和数据类型机制。 提供一个抽象表,这样用户就不需要关注数据存储的方式和地址。 为类似Pig、MapReduce及Hive这些数据处理工具提供互操作性。 Chukwa: Chukwa是基于Hadoop的大集群监控系统,由yahoo贡献。 Cloudera Manager功能 cloudera manager有四大功能: (1)管理:对集群进行管理,如添加、删除节点等操作。 (2)监控:监控集群的健康情况,对设置的各种指标和系统运行情况进行全面监控。 (3)诊断:对集群出现的问题进行诊断,对出现的问题给出建议解决方案。 (4)集成:对hadoop的多组件进行整合。 示例,管理4集群: 管理的服务包括: Cloudera Manager架构 cloudera manager的核心是管理服务器,该服务器承载管理控制台的Web服务器和应用程序逻辑,并负责安装软件,配置,启动和停止服务,以及管理上的服务运行群集。 Cloudera Manager Server由以下几个部分组成: Agent:安装在每台主机上。该代理负责启动和停止的过程,拆包配置,触发装置和监控主机。 Management Service:由一组执行各种监控,警报和报告功能角色的服务。 Database:存储配置和监视信息。通常情况下,多个逻辑数据库在一个或多个数据库服务器上运行。例如,Cloudera的管理服务器和监控角色使用不同的逻辑数据库。 Cloudera Repository:软件由Cloudera 管理分布存储库。 Clients:是用于与服务器进行交互的接口: Admin Console - 基于Web的用户界面与管理员管理集群和Cloudera管理。 API - 与开发人员创建自定义的Cloudera Manager应用程序的API。
web访问日志 主要是指用户在访问某网站的时候产生的日志信息,采集方式包括前端Javascript埋码采集和后端服务器日志采集两种。 前端采集目前主要以javascript为主,收集用户数据。 后端服务器日志根据网站架构,一般以nginx和tomcat等加上业务日志的采集为主。 对于数据的权威和准确性而言,应该首先以后端服务器产生的数据为主,配合前端采集的数据来进行整体的分析和挖掘。 日志分析流程 日志分析流程如下: 数据采集:包括埋码和业务数据收集两种。 数据传输:包括实时和离线传输两种。 存储:建立统一的数据仓库。 分析和建模:数理统计和数据挖掘。 可视化展示:分析结果、挖掘结果及分析报告。 nginx样例数据 样例数据格式: 124.42.13.230 - - [18/Sep/2013:06:57:50 +0000] "GET /shoppingMall?ver=1.2.1 HTTP/1.1" 200 7200 "http://www.baidu.com.cn" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; BTRS101170; InfoPath.2; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727)" 格式分析: 1、访客ip地址:124.42.13.230 2、访客用户信息: - - 3、请求时间:[18/Sep/2013:06:57:50 +0000] 4、请求方式:GET 5、请求的url:/shoppingMall?ver=1.10.2 6、请求所用协议:HTTP/1.1 7、响应码:200 8、返回的数据流量:7200 9、访客的来源url:http://www.baidu.com.cn 10、访客所用浏览器:Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; BTRS101170; InfoPath.2; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727) 对于这种数据,可以交叉组合,开成多维度的数据分析与挖掘。 web日志挖掘的目标 web日志挖掘的目标: 1、以改进站点设计为目标,根据挖掘到的用户频繁访问路径重新调整链接关系。 2、以分析网站性能为目标,统计出用户经常浏览的页面及访问时间等。 3、以理解用户意图为目标,根据这些信息对用户的请求做专门的定制,然后将页面返回给用户。 使用分为: 1、web结构挖掘。 2、web内容挖掘。 3、web使用挖掘。 web日志挖掘流程 分为数据收集、数据预处理、模式发现和模式分析几部分。 作者:skyme 联系方式: 邮箱【cloudskyme@163.com】 QQ【270800073】 本文版权归作者和云栖社区共同所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
单例模式介绍 单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例。 对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。 单例模式七种写法 第一种(懒汉,线程不安全) public class Singleton { private static Singleton instance; private Singleton (){} public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } 不适合多线程。 第二种(懒汉,线程安全) public class Singleton { private static Singleton instance; private Singleton (){} public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } 这种方式线程安全,但是效率很低。 第三种(饿汉) public class Singleton { private static Singleton instance = new Singleton(); private Singleton (){} public static Singleton getInstance() { return instance; } } 这种方式基于classloder机制避免了多线程的同步问题,不过,instance在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用getInstance方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化instance显然没有达到lazy loading的效果。 第四种(饿汉,变种) public class Singleton { private Singleton instance = null; static { instance = new Singleton(); } private Singleton (){} public static Singleton getInstance() { return this.instance; } } 和第三种差不多,都是在类初始化即实例化instance。 第五种(静态内部类) public class Singleton { private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton (){} public static final Singleton getInstance() { return SingletonHolder.INSTANCE; } } 这种方式同样利用了classloder的机制来保证初始化instance时只有一个线程,它跟第三种和第四种方式不同的是(很细微的差别):第三种和第四种方式是只要Singleton类被装载了,那么instance就会被实例化(没有达到lazy loading效果),而这种方式是Singleton类被装载了,instance不一定被初始化。因为SingletonHolder类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance。想象一下,如果实例化instance很消耗资源,我想让他延迟加载,另外一方面,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化instance显然是不合适的。这个时候,这种方式相比第三和第四种方式就显得很合理。 第六种(枚举) public enum Singleton { INSTANCE; public void whateverMethod() { } } 这种方式是Effective Java作者Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,可谓是很坚强的壁垒啊,不过,个人认为由于1.5中才加入enum特性,用这种方式写不免让人感觉生疏,在实际工作中,我也很少看见有人这么写过。 第七种(双重校验锁) public class Singleton { private volatile static Singleton singleton; private Singleton (){} public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } } 第二种的升级版,俗称双重检查锁定。 scala单例 单例模式就控制类实例的个数,通过伴生对象来访问类的实例就提供了控制实例个数的机会。一个简单示例: class Worker private{ def work() = println("I am the only worker!") } object Worker{ val worker = new Worker def GetWorkInstance() : Worker = { worker.work() worker } } object Job{ def main(args: Array[String]) { for (i <- 1 to 5) { Worker.GetWorkInstance(); } } } class Worker private声明了Worker的首构造函数是私有的,这样Worker的所有构造函数都不能直接被外部调用,因为所有从构造函数都会首先调用其他构造函数(可以是主构造函数,也可以是从构造函数),结果就是主构造函数是类的唯一入口点。 另一方面,Worker.GetWorkInstance();有点类似静态函数调用,但在Scala中这是不对的。Scala会隐式地调用apply来创建一个伴生对象的实例。Scala是一个纯粹的面向对象语言,不允许有任何破坏对象模型的机制存在,比如类的静态变量、函数等。 作者:skyme 联系方式: 邮箱【cloudskyme@163.com】 QQ【270800073】 本文版权归作者和云栖社区共同所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
什么是精细化运营 企业运营对于企业来说是非常重要的,因为良好的运营体系会让企业在市场宣传中轻松应对各种情况。当我们迈入数据时代的时候,企业在运营上相对应的也发生了改变,从最初的粗放式运营逐渐过渡到精细化运营。精细化运营就是能够充分了解企业的运营情况,做到知已知彼。 跟踪监测的点 主要包括以下部分: 模块的访问记录——对比新老用户的访问比,如果新用户的访问占比远远大于老用户的访问占比,那这个功能就是个鸡肋,因为基本上只有新用户在访问。(注册等新用户特性模块除外)。 模块的留存情况——我们知道一般情况下所谓的留存都是指用户有没有在一段时间后(天,周,月)持续的访问网站,而留存本身的意义也在于观察一段时间内用户的持续访问情况,但对于留存的观察,“访问网站”远远不及使用产品的核心功能,例如电商应用需要关注用户持续使用的是浏览商品、加入购物车或下订单功能等;对于图片社区,可能关注的就是用户浏览图片或者上传图片;而对一个社交应用来说可能关注的就是用户有没有持续的互动。对于内容类网站来说可能就是是否持续的阅读。 排序和模块展示的位置优化——在屏幕上的每一个位置都有不一样的转化率,所以如果很多可能吸引用户的功能放在不好的位置,也会导致用户流失。但目前对于很多模块的展示位置,或者类似于某块内容的分类排序,一般基于产品经理的原型设计或者运营编辑的经验判断。因此在产品发布之后,我们需要关注的是这些模块或者分类的持续访问情况,然后根据用户访问数据去优化排序,留存高的模块当然要放在好的位置,留存低的就要持续优化了。 路径优化——上面所述的点,关注的更多是持续访问的意义,也就是产品功能的长期价值。在产品使用过程中,有很多流程性的操作,比如: “阅读”——“分享” “注册”——“填写资料”——“注册成功” “浏览商品”——“加入购物车”——“下订单” 每一步操作背后都隐含着用户的交互,所以交互设计不合理、操作繁琐或隐蔽、产品有bug、性能不好都会造成用户的流失。 怎样与产品结合 那么数据分析到底该怎样和产品结合呢?其实等同于精益创业打磨一个最小化产品,然后利用数据衡量再规模推广一样,数据分析也是这样一个过程。我们需要一开始选取一部分的用户流量去测试我们的产品,当数据还行的时候,再应用到全市场,看看下面这个图: 逻辑是:确立目标,找到分析模型,然后利用分析方法进行分析,最后随着迭代的过程周而复始。 网站分析之热图 热图模式中间的热图区域显示的是,在选定的时间段和页面(而不只是热图中的当前可视区域)中,点击量在数据总量里前 1000 的元素里,有内容或有链接的元素。没有内容和链接的元素将会被过滤,以防止混淆元素的干扰。热图同时也是产品优化产品的重要手段之一,可以通过热力点击的区域来盾是否点击和喜好程度。 网站分析之留存 对预先设定的目标进行展示,比如次日留存等指标。留存分析包括:用户留存、产品功能留存、自定义留存。 用户留存:分析用户回访网站、App的留存情况,包括新用户和所有用户留存分析。通常情况下,用户在早期流失现象非常严重。产品需要让用户快速容易的体验到产品的价值。一旦用户发现产品对自己的价值,继续使用和探索产品新功能的概率就会增大很多。对比分析用户进行过的行为可以帮助您发现高留存率的行为,寻找行为与留存的相关性, 还可以通过维度、分群对比了解不同特征的新用户留存分布情况,并为您的决策提供数据支持。 产品功能留存: 分析用户对不同产品功能的使用粘性与活跃度。一般我们不仅需要关注整个网站/App的留存,还需要关注核心行为的留存率,比如重复购买的情况。对产品进行迭代时,我们还可以使用产品功能留存观测这个功能的留存率整体有没有提高;或者例如电商网站,发现用户对某一类商品购买的留存率很高,便可以采取相应的营销活动。 自定义留存:可自定义起始、回访行为,进行更多情景下的留存分析。 例如您想了解新用户多久才开始使用某个产品功能,您可以选择起始行为是任意行为,回访行为是点击这个功能的按钮,来观测新用户对这个功能使用时间的分布情况,寻找到合适的转化周期。您还可以通过维度对比与分群对比,进行更深度挖掘。 网站分析之转化 漏斗是衡量转化效果、进行转化分析的重要工具。这也是观察运营效果的重要手段之一,对于转化率不能达到阈值的情况,进行深入的分析,找到原因,对症下药。 网站分析之用户分群 用户分群是对用户根据一定的规则进行切分。可以使用基于分析或者业务结合的方法,也可以使用模型的方法,下图是使用RFM对数据进行切分的实例。
日志收集 日志收集包括服务器日志收集和埋码日志收集两种。 服务器日志主要是nginx、tomcat等产生的访问和业务日志。 埋码收集主要是某些服务器无法收集,需要在前端进行收集的数据。 收集流程 日志处理是指将消息队列用在日志处理中,比如Kafka的应用,解决大量日志传输的问题。 日志采集客户端,负责日志数据采集,定时写受写入Kafka队列; Kafka消息队列,负责日志数据的接收,存储和转发; 日志处理应用:订阅并消费kafka队列中的日志数据; 下面是一个应用的实例图 存储可以是Elasticsearch,对数据进行实时分析。 为什么kafka Kafka 是分布式发布-订阅消息系统。它最初由 LinkedIn 公司开发,使用 Scala语言编写,之后成为 Apache 项目的一部分。Kafka 是一个分布式的,可划分的,多订阅者,冗余备份的持久性的日志服务。它主要用于处理活跃的流式数据。如果对时时性要求较高的话,可以使用这种方案。 它具备以下特点: 同时为发布和订阅提供高吞吐量。据了解,Kafka 每秒可以生产约 25 万消息(50 MB),每秒处理 55 万消息(110 MB)。 可进行持久化操作。将消息持久化到磁盘,因此可用于批量消费,例如 ETL,以及实时应用程序。通过将数据持久化到硬盘以及 replication 防止数据丢失。 分布式系统,易于向外扩展。所有的 producer、broker 和 consumer 都会有多个,均为分布式的。无需停机即可扩展机器。 消息被处理的状态是在 consumer 端维护,而不是由 server 端维护。当失败时能自动平衡。 支持 online 和 offline 的场景。 kafka的测试效果 下面是单机情况下的测试效果: kafka的核心概念 kafka中的核心概念如下: Producer 特指消息的生产者 Consumer 特指消息的消费者 Consumer Group 消费者组,可以并行消费Topic中partition的消息 Broker:缓存代理,Kafa 集群中的一台或多台服务器统称为 broker Topic:特指 Kafka 处理的消息源(feeds of messages)的不同分类。 Partition:Topic 物理上的分组,一个 topic 可以分为多个 partition,每个 partition 是一个有序的队列。partition 中的每条消息都会被分配一个有序的 id(offset)。 Message:消息,是通信的基本单位,每个 producer 可以向一个 topic(主题)发布一些消息。 Producers:消息和数据生产者,向 Kafka 的一个 topic 发布消息的过程叫做 producers。 Consumers:消息和数据消费者,订阅 topics 并处理其发布的消息的过程叫做 consumers。 kafka的整体流程 kafka的整体流程: 数据通过flume在客户端进行代理,收集各种日志信息,整体模式使用生产者,消费者的模型。 producer可以根据配置设置发送的时间段。 broker中分为不同的topic,topic中又可以分为不同的partition,这个有点儿类似于数据库中的分区表,对于数据量大的情况下非常适合。 customer负责消费消息日志,如果需要时时消费,则可以使用storm或者spark streaming,如果离线消费,可以使用mapreduce。 kafka总结 kafka可以完全应用到不同的业务场景中,配合zookeeper,保证系统的高可用性。 作者:skyme 联系方式: 邮箱【cloudskyme@163.com】 QQ【270800073】 本文版权归作者和云栖社区共同所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
从trie树说起 Trie树,又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。 Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构,如英文字母的字典树是一个26叉树,数字的字典树是一个10叉树。 Trie树可以利用字符串的公共前缀来节约存储空间。如下图所示,该trie树用10个节点保存了6个字符串tea,ten,to,in,inn,int: trie树的优缺点 在该trie树中,字符串in,inn和int的公共前缀是“in”,因此可以只存储一份“in”以节省空间。当然,如果系统中存在大量字符串且这些字符串基本没有公共前缀,则相应的trie树将非常消耗内存,这也是trie树的一个缺点。 Trie树的基本性质可以归纳为: (1)根节点不包含字符,除根节点意外每个节点只包含一个字符。 (2)从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串。 (3)每个节点的所有子节点包含的字符串不相同。 trie树的demo Ansj作者ansjsun为此数据结构专门开了一个项目,clone下来之后可以用作者提供的一个demo进行测试: import java.io.BufferedReader; import java.io.StringReader; import love.cq.domain.Forest; import love.cq.library.Library; import love.cq.splitWord.GetWord; /** * @author feng * */ public class TreeSplitTest { /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { /** * 词典的构造.一行一个词后面是参数.可以从文件读取.可以是read流. */ String dic = "中国\t1\tzg\n人名\t2\n中国人民\t4\n人民\t3\n孙健\t5\nCSDN\t6\njava\t7\njava学习\t10\n"; Forest forest = Library.makeForest(new BufferedReader(new StringReader( dic))); /** * 删除一个单词 */ Library.removeWord(forest, "中国"); /** * 增加一个新词 */ Library.insertWord(forest, "中国人"); String content = "中国人名识别是中国人民的一个骄傲.孙健人民在CSDN中学到了很多最早iteye是java学习笔记叫javaeye但是java123只是一部分"; GetWord udg = forest.getWord(content); String temp = null; while ((temp = udg.getFrontWords()) != null) System.out.println(temp + "\t\t" + udg.getParam(1) + "\t\t" + udg.getParam(2)); } } 以上代码完全来自ansjsun的demo,运行后的输出结果为: 这段demo的目的是利用一个小词典对后面一句话进行分词,词典被用来构造了一颗Trie树,也就是代码中的forest。这个版本的分词器中需要引入条件概率(隐马尔可夫模型)提高分词的准确性。 CRF 简介入门 Conditional Random Field:条件随机场,一种机器学习技术(模型)。 CRF由John Lafferty最早用于NLP技术领域,其在NLP技术领域中主要用于文本标注,并有多种应用场景,例如: 分词(标注字的词位信息,由字构词) 词性标注(标注分词的词性,例如:名词,动词,助词) 命名实体识别(识别人名,地名,机构名,商品名等具有一定内在规律的实体名词) 使用CRF进行中文分词 1)CRF VS 词典统计分词 基于词典的分词过度依赖词典和规则库,因此对于歧义词和未登录词的识别能力较低;其优点是速度快,效率高 CRF代表了新一代的机器学习技术分词,其基本思路是对汉字进行标注即由字构词(组词),不仅考虑了文字词语出现的频率信息,同时考虑上下文语境,具备较好的学习能力,因此其对歧义词和未登录词的识别都具有良好的效果;其不足之处是训练周期较长,运营时计算量较大,性能不如词典分词 2)CRF VS HMM,MEMM 首先,CRF,HMM(隐马模型),MEMM(最大熵隐马模型)都常用来做序列标注的建模,像分词、词性标注,以及命名实体标注 隐马模型一个最大的缺点就是由于其输出独立性假设,导致其不能考虑上下文的特征,限制了特征的选择 最大熵隐马模型则解决了隐马的问题,可以任意选择特征,但由于其在每一节点都要进行归一化,所以只能找到局部的最优值,同时也带来了标记偏见的问题,即凡是训练语料中未出现的情况全都忽略掉 条件随机场则很好的解决了这一问题,他并不在每一个节点进行归一化,而是所有特征进行全局归一化,因此可以求得全局的最优值。 CRF 原理 1)CRF把分词当做字的词位分类问题,通常定义字的词位信息如下: 词首,常用B表示 词中,常用M表示 词尾,常用E表示 单子词,常用S表示 2)CRF分词的过程就是对词位标注后,将B和E之间的字,以及S单字构成分词 3)CRF分词实例: 原始例句:我爱北京天安门 CRF标注后:我/S 爱/S 北/B 京/E 天/B 安/M 门/E 分词结果:我/爱/北京/天安门 CRF 分词及使用 目前常见的CRF工具包有pocket crf, flexcrf 车crf++。下面的链接是使用CRF进行中文分词的示例: http://x-algo.cn/index.php/2016/02/27/crf-of-chinese-word-segmentation/ 总结 在下面将介绍中文分词中的几个经典算法,包括正向最大匹配、逆向最大匹配、逐词匹配、最少切分和全切分。 作者:skyme 出处: http://www.niubua.com/ 联系方式: 邮箱【cloudskyme@163.com】 QQ【270800073】 本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
语料库 关于语料库的三点基本认识:语料库中存放的是在语言的实际使用中真实出现过的语言材料;语料库是以电子计算机为载体承载语言知识的基础资源;真实语料需要经过加工(分析和处理),才能成为有用的资源。 语料库特征 语料库有三点特征 1)语料库中存放的是在语言的实际使用中真实出现过的语言材料,因此例句库通常不应算作语料库; 2)语料库是承载语言知识的基础资源,但并不等于语言知识; 3)真实语料需要经过加工(分析和处理),才能成为有用的资源。 语料库的发展经历了前期(计算机发明以前),第一代语料库,第二代语料库,到第三代语料库。 语料库在线 此网址内有大量的语料库信息: 语料库在线 使用CRF++进行中文分词 首先下载CRF++,我下载的地址是: CRF++ toolkit 0.58 下载完成后,上传到你的工作目录: 解压缩,然后安装: ./configure make sudo make install 然后下载人民日报语料: 人民日报语料 也可以到群nlp研究与讨论 413423481群文件中下载。 生成训练数据 通过下面python脚本,根据人民日报的语料库生成crf的测试和训练数据。原始数据中随机10%是测试数据,90%是训练数据。程序打印出来了不少调试信息,可以忽略。生成训练数据的时候,支持4tag和6tag两个格式,6tag的格式是: S,单个词;B,词首;E,词尾;M1/M2/M,词中 4tag和6tag的区别就是没有词中顺序状态。具体代码: #coding=utf8 import sys #home_dir = "D:/source/NLP/people_daily//" home_dir = "./" def splitWord(words): uni = words.decode('utf-8') li = list() for u in uni: li.append(u.encode('utf-8')) return li #4 tag #S/B/E/M def get4Tag(li): length = len(li) #print length if length == 1: return ['S'] elif length == 2: return ['B','E'] elif length > 2: li = list() li.append('B') for i in range(0,length-2): li.append('M') li.append('E') return li #6 tag #S/B/E/M/M1/M2 def get6Tag(li): length = len(li) #print length if length == 1: return ['S'] elif length == 2: return ['B','E'] elif length == 3: return ['B','M','E'] elif length == 4: return ['B','M1','M','E'] elif length == 5: return ['B','M1','M2','M','E'] elif length > 5: li = list() li.append('B') li.append('M1') li.append('M2') for i in range(0,length-4): li.append('M') li.append('E') return li def saveDataFile(trainobj,testobj,isTest,word,handle,tag): if isTest: saveTrainFile(testobj,word,handle,tag) else: saveTrainFile(trainobj,word,handle,tag) def saveTrainFile(fiobj,word,handle,tag): if len(word) > 0: wordli = splitWord(word) if tag == '4': tagli = get4Tag(wordli) if tag == '6': tagli = get6Tag(wordli) for i in range(0,len(wordli)): w = wordli[i] h = handle t = tagli[i] fiobj.write(w + '\t' + h + '\t' + t + '\n') else: #print 'New line' fiobj.write('\n') #B,M,M1,M2,M3,E,S def convertTag(tag): fiobj = open( home_dir + 'people-daily.txt','r') trainobj = open( home_dir + tag + '.train.data','w' ) testobj = open( home_dir + tag + '.test.data','w') arr = fiobj.readlines() i = 0 for a in arr: i += 1 a = a.strip('\r\n\t ') if a=="":continue words = a.split(" ") test = False if i % 10 == 0: test = True for word in words: print "---->", word word = word.strip('\t ') if len(word) > 0: i1 = word.find('[') if i1 >= 0: word = word[i1+1:] i2 = word.find(']') if i2 > 0: w = word[:i2] word_hand = word.split('/') print "----",word w,h = word_hand #print w,h if h == 'nr': #ren min #print 'NR',w if w.find('·') >= 0: tmpArr = w.split('·') for tmp in tmpArr: saveDataFile(trainobj,testobj,test,tmp,h,tag) continue if h != 'm': saveDataFile(trainobj,testobj,test,w,h,tag) if h == 'w': saveDataFile(trainobj,testobj,test,"","",tag) #split trainobj.flush() testobj.flush() if __name__ == '__main__': if len(sys.argv) < 2: print 'tag[6,4] convert raw data to train.data and tag.test.data' else: tag = sys.argv[1] convertTag(tag) 将人民日报语料库跟python放在同一目录,生成数据时,通过最后一个参数是4还是6区别生成4tag数据还是6tag数据。执行python角本: #生成6tag python get_crf_train_test_data.py 6 #生成4tag python get_crf_train_test_data.py 4 执行后可以看到: 进入到CRF++-0.58/example/seg的目录下可以看到: 编写模板: # Unigram U00:%x[-1,0] U01:%x[0,0] U02:%x[1,0] U03:%x[-1,0]/%x[0,0] U04:%x[0,0]/%x[1,0] U05:%x[-1,0]/%x[1,0] 执行训练和测试: #!/bin/sh crf_learn -f 3 -c 4.0 template 6.train.data 6.model > 6.train.rst crf_test -m 6.model 6.test.data > 6.test.rst 最后计算一下F值: #!/usr/bin/python # -*- coding: utf-8 -*- import sys if __name__=="__main__": try: file = open(sys.argv[1], "r") except: print "result file is not specified, or open failed!" sys.exit() wc_of_test = 0 wc_of_gold = 0 wc_of_correct = 0 flag = True for l in file: if l=='\n': continue _, _, g, r = l.strip().split() if r != g: flag = False if r in ('E', 'S'): wc_of_test += 1 if flag: wc_of_correct +=1 flag = True if g in ('E', 'S'): wc_of_gold += 1 print "WordCount from test result:", wc_of_test print "WordCount from golden data:", wc_of_gold print "WordCount of correct segs :", wc_of_correct #查全率 P = wc_of_correct/float(wc_of_test) #查准率,召回率 R = wc_of_correct/float(wc_of_gold) print "P = %f, R = %f, F-score = %f" % (P, R, (2*P*R)/(P+R)) 下图是得到的测试结果: 【参考文章列表】 CRF++中文分词使用指南 CRF++中文分词 作者:skyme 出处: http://www.niubua.com/ 联系方式: 邮箱【cloudskyme@163.com】 QQ【270800073】 本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
什么是自然语言 自然语言处理是计算机科学领域与人工智能领域中的一个重要方向。它研究能实现人与计算机之间用自然语言进行有效通信的各种理论和方法。自然语言处理是一门融语言学、计算机科学、数学于一体的科学。因此,这一领域的研究将涉及自然语言,即人们日常使用的语言,所以它与语言学的研究有着密切的联系,但又有重要的区别。自然语言处理并不是一般地研究自然语言,而在于研制能有效地实现自然语言通信的计算机系统,特别是其中的软件系统。因而它是计算机科学的一部分。 自然语言就是人类交流的一种工具。 问题 从下图中看出,中文检索的最高准确率不足: 全世界正在使用的语言有1900多种: 语言分布情况: 语言应用情况预测,到2050年: 图灵测试 图灵测试一词来源于计算机科学和密码学的先驱阿兰·麦席森·图灵写于1950年的一篇论文《计算机器与智能》。阿兰·麦席森·图灵1950年设计出这个测试,其内容是,如果电脑能在5分钟内回答由人类测试者提出的一系列问题,且其超过30%的回答让测试者误认为是人类所答,则电脑通过测试。 应用 多语言翻译、安全、信息检索、自动文摘、问答系统、信息过滤、信息抽取、文档分类、文字编辑和自动校正、语言教学和文字识别、语音识别、语音合成、说话人识别等。 作者:skyme 出处: http://www.niubua.com/ 联系方式: 邮箱【cloudskyme@163.com】 QQ【270800073】 本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
随机森林是一个高度灵活的机器学习方法,拥有广泛的应用前景,从市场营销到医疗保健保险。 既可以用来做市场营销模拟的建模,统计客户来源,保留和流失。也可用来预测疾病的风险和病患者的易感性。 随机森林是一个可做能够回归和分类。 它具备处理大数据的特性,而且它有助于估计或变量是非常重要的基础数据建模。 这是一篇关于使用Python来实现随机森林文章。 什么是随机森林? 随机 森林 是 几乎 任何 预测 问题 (甚至 非直线 部分) 的固有 选择 。 它是 一个 相对较 新 的 机器 学习 的 策略 ( 在 90 年代产生于 贝尔 实验室 ) 和 它 可以 几乎用于 任何方面 。 它 属于 机器 学习 算法 一大类—– 集成学习 方法 。 集成学习 集成学习通过建立几个模型组合的来解决单一预测问题。它的工作原理是生成多个分类器/模型,各自独立地学习和作出预测。这些预测最后结合成单 预测,因此优于任何一个单分类的做出预测。 随机森林是集成学习的一个子类,由于它依靠于策率树的合并。你可以在这找到用python实现集成学习的文档: Scikit 学习文档。 随机决策树 我们 知道 随机 森林 是 其他 的模型 聚合, 但 它 聚合 了什么 类型 模型 ? 你 可能 已经 从 其 名称 、 随机 森林 聚合 分类(或 回归) 的 树 中猜到。 决策 树 是 由 一 系列 的 决策的组合, 可 用于 分类 观察 数据集 。 随机森林 算法引入了一个随机森林来 自动 创建 随机 决策 树 群 。 由于 树 随机 生成 的树, 大部分的树(或许 99.9%树) 不 会 对 学习 的 分类/回归 问题 都 有意义 。 如果 观察到 长度 为 45 ,蓝 眼睛 , 和 2 条腿 , 就 被 归类 为 红色 。 树的投票 所以10000个(概率上)糟糕的模型有TMD什么好的?好吧,这样确实没什么特别的好处。但是随着很多糟糕的决策树被生成,其中也会有很少确实很优秀的决策树。 当你要做预测的时候,新的观察到的特征随着决策树自上而下走下来,这样一组观察到的特征将会被贴上一个预测值/标签。一旦森林中的每棵树都给出了预测值/标签,所有的预测结果将被归总到一起,所有树的模式投票被返回做为最终的预测结果。 简单来说,99.9%不相关的树做出的预测结果涵盖所有的情况,这些预测结果将会彼此抵消。少数优秀的树的预测结果将会超脱于芸芸“噪音”,做出一个好的预测。 为什么你让我用它? 简单 随机森林就是学习方法中的Leatherman呀。你几乎可以把任何东西扔进去,它基本上都是可供使用的。在估计推断映射方面特别好用,以致都不需要像SVM那样做很多调试(也就是说对于那些最后期限很紧的家伙们真是太棒了)。 [译者注:Leatherman就是那家生产多功能折叠刀的公司,类似瑞士军刀] 一个映射的例子 随机森林在没有精心准备的数据映射的情况下也能学习。以方程f(x) = log(x)为例。 制造一些假数据,并且加上一点儿噪音。 import numpy as np x = np.random.uniform(1, 100, 1000) y = np.log(x) + np.random.normal(0, .3, 1000) 如果 我们 建立了 一个 基本 的 线性 模型 通过使用 x 来预测y, 我们需要 作 一 条 直线 , 算是 平分 log (x) 函数。 而 如果 我们 使用 一个 随机 的 森林 , 它 不会 更 好 的 逼近 log (x) 曲线 并能够使得它更像实际函数。 你 也许会说 随机 森林 有点 扰乱了 log(x) 函数 。 不管怎样 , 我 都认为 这 做了一个 很 好 的 说明 如何 随机 森林 并 未绑定于 线性 约束 。 使用 变量选择 随机森林最好的用例之一是特征选择。尝试很多决策树变种的一个副产品就是你可以检测每棵树中哪个变量最合适/最糟糕。 当一棵树使用一个变量,而另一棵不使用这个变量,你就可以从是否包含这个变量来比较价值的减少或增加。优秀的随机森林实现将为你做这些事情,所以你需要做的仅仅是知道去看那个方法或参数。 在下述的例子中,我们尝试去指出对于将酒分为红酒或者白酒哪个变量是最重要的。 分类 随机森林也很善于分类。它可以被用于为多个可能目标类别做预测,它也可以被校正输出概率。你需要注意的一件事情是过拟合。随机森林容易产生过拟合,特别是在数据集相对小的时候。当你的模型对于测试集合做出“太好”的预测的时候就应该怀疑一下了。 产生过拟合的一个原因是在模型中只使用相关特征。然而只使用相关特征并不总是事先准备好的,使用特征选择(就像前面提到的)可以使其更简单。 回归 是的,它也可以做回归。 我们已经发现随机森林——不像其它算法——对分类变量或者分类变量和真实变量混合学习的非常好。具有高基数(可能值的#)的分类变量是很棘手的,所以在你的口袋中放点儿这样的东西将会是非常有用的。 一个简短的python例子 Scikit-Learn是开始使用随机森林的一个很好的方式。scikit-learn API在所以算法中极其的一致,所有你测试和在不同的模型间切换非常容易。很多时候,我从一些简单的东西开始,然后转移到了随机森林。 随机森林在scikit-learn中的实现最棒的特性是n_jobs参数。这将会基于你想使用的核数自动地并行设置随机森林。这里是scikit-learn的贡献者Olivier Grisel的一个很棒的报告,在这个报告中他谈论了使用20个节点的EC2集群训练随机森林。 from sklearn.datasets import load_iris from sklearn.ensemble import RandomForestClassifier import pandas as pd import numpy as np iris = load_iris() df = pd.DataFrame(iris.data, columns=iris.feature_names) df['is_train'] = np.random.uniform(0, 1, len(df)) <= .75 df['species'] = pd.Factor(iris.target, iris.target_names) df.head() train, test = df[df['is_train']==True], df[df['is_train']==False] features = df.columns[:4] clf = RandomForestClassifier(n_jobs=2) y, _ = pd.factorize(train['species']) clf.fit(train[features], y) preds = iris.target_names[clf.predict(test[features])] pd.crosstab(test['species'], preds, rownames=['actual'], colnames=['preds']) 看起来很不错! 结语 随机森林相当容易使用,而且很强大。对于任何建模,都要注意过拟合。如果你有兴趣用R语言开始使用随机森林,那么就签出randomForest包。
首先读入一个时间序列:从1946年1月到1959年12月的纽约每月出生人口数量(由牛顿最初收集)数据集可以从此链接下载(http://robjhyndman.com/tsdldata/data/nybirths.dat)。我们将数据读入R,并且存储到一个时间序列对象中,输入以下代码: births<- scan("http://robjhyndman.com/tsdldata/data/nybirths.dat") birthstimeseries<-ts(births,frequency=12,start=c(1946,1)) 月度数据就设定frequency=12,季度数据就设定frequency=4;“start”参数来指定收集数据的第一年和这一年第一个间隔期。 接下来我们用plot函数绘制时间序列图: plot.ts(birthstimeseries) 可以看到这个时间序列在一定月份存在的季节性变动:在每年的夏天都有一个出生峰值,在冬季的时候进入波谷。同样,这样的时间序列也可能是一个相加模型,随着时间推移,季节性波动时大致稳定的而不是依赖于时间序列水平,且对着时间的变化,随机波动看起来也是大致稳定的。 接下来我们来分解时间序列,时间序列分为:非季节性数据和季节性数据 一个非季节性时间序列包含一个趋势部分和一个不规则部分。分解时间序列即为试图把时间序列拆分成这些成分,也就是说,需要估计趋势的和不规则的这两个部分。 一个季节性时间序列包含一个趋势部分,一个季节性部分和一个不规则部分。分解时间序列就意味着要把时间序列分解称为这三个部分:也就是估计出这三个部分。 上述的婴儿出生是明显季节性时间序列,我们采用R提供的“decompose()”函数分解该时间序列: birthstimeseriescomponents <- decompose(birthstimeseries) 估计出的季节性、趋势的和不规则部分现在被存储在变量birthstimeseriescomponents$seasonal, birthstimeseriescomponents$trend和 birthstimeseriescomponents$random 中。 我们可以分别画出这三部分,观察其特性: plot(birthstimeseriescomponents) 图展现出了原始的时间序列图(顶部),估计出的趋势部分图(第二部份),估计出的季节性部分(第三个部分),估计得不规则部分(底部)。我们可以看到估计出的趋势部分从1947年的24下降到1948年的22,紧随着是一个稳定的增加直到1949年的27。 上述示例充分展示了时间序列的多模型加和性,该属性也是时间序列的一个很重要的属性,每拿到一个时间序列,我们首先需要判断该时间序列是否可以用相加模型来描述,在确定了加和属性后去考虑如何分解时间序列,以下举一个例子说明(澳大利亚昆士兰州海滨度假圣地的纪念品商店从1987年1月到1987年12月的每月销售数据)。我们首先画出该序列,找个整体的感知: souvenir <- scan("http://robjhyndman.com/tsdldata/data/fancy.dat") souvenirtimeseries <- ts(souvenir, frequency=12, start=c(1987,1)) plot.ts(souvenirtimeseries) 结果如下: 该序列看上去不适合时间,因为该序列的季节波动性和随机波动的大小随着时间序列逐步上升。为了使该序列符合标准的时间序列从而采用相加模型描述,我们对原始数据取自然对数进行转换: logsouvenirtimeseries <- log(souvenirtimeseries) plot.ts(logsouvenirtimeseries) 结果如下: 我们可以看到季节性波动和随机变动的大小在对数变换后的时间序列上,随着时间推移,季节性波动和随机波动的大小是大致恒定的,并且不依赖于时间序列水平。因此转换后的时间序列可以用相加模型进行描述,我们对变化后的序列进行分解: logsouvenirtimeseriesComponents <- decompose(logsouvenirtimeseries) plot(logsouvenirtimeseriesComponents) 观察该图,我们也可以看出随着时间的推移,随机和季节的波动都是稳定的,再次证明我们的转换是有作用的。
ggplot2 R的作图工具包,可以使用非常简单的语句实现非常复杂漂亮的效果。 qplot 加载qplot library(ggplot2) # 测试数据集,ggplot2内置的钻石数据 qplot(carat, price, data = diamonds) dsmall <- diamonds[sample(nrow(diamonds), 100), ] #对diamonds数据集进行抽样 #1. 按color,size,shape的基本分类可视化 #1.1 简单的散点图(利用color分类,不同颜色的钻石由不同颜色的点代表) #1.2. 简单的散点图(利用shape分类,不同的切割方式由不同形状的点代表) #2. 绘制不同类型的图表:geom参数 qplot(x,y,data=data,geom="")中的geom=""用来控制输出的图形类型 I. 两变量图 (1) geom="points",默认参数,绘制散点图(x,y) (2) geom="smooth" 绘制平滑曲线(基于loess, gam, lm ,rlm,glm) (3) geom="boxplot" 绘制箱线图 ,当x为属性变量(factor),y为数值变量时 II.单变量图 (4) geom="histogram",直方图 (5) geom="density",核密度估计图 (6) geom="bar",条形图barchart III.时间序列 (7) geom="line",折线图,可用于时间序列(当x=date) (8) geom="path",路径图(参见后文) # 2.1 同时绘制散点图+平滑直线 qplot(carat, price, data = dsmall, geom=c("point","smooth")) #参数调整:method=""等 #(a). method = "loess", 默认平滑算法, 通过span=调整窗宽, span=0(波动) 到 span=1(光滑) qplot(carat, price, data = dsmall, geom = c("point", "smooth"), method = "loess",span=0.2) # (b). method = "gam": GAM 在大数据时比loess高效,需要载入 mgcv 包 library(mgcv) qplot(carat, price, data = dsmall, geom = c("point", "smooth"), method="gam", formula = y ~ s(x)) # (c). method="lm", 线性平滑 qplot(carat, price, data = dsmall, geom = c("point", "smooth"), method = "lm") # method="lm",formula = y ~ ns(x, 3),三次自然样条,需要载入splines包 library(splines) qplot(carat, price, data = dsmall, geom = c("point", "smooth"), method = "lm", formula = y ~ ns(x, 3)) # method = "rlm", robust linear model, 受异常值影响小,需要载入MASS包 library(MASS) qplot(carat, price, data = dsmall, geom = c("point", "smooth"), method = "rlm") # 2.2:x为属性变量,y为连续变量,绘制boxplot qplot(color, price/carat, data=diamonds,geom="boxplot") # 2.3:单变量,直方图 qplot(carat, data = diamonds, geom = "histogram") #2.4: 单变量,核密度估计图 qplot(carat, data = diamonds, geom = "density") # 按不同颜色绘制的density图 qplot(carat, data = diamonds, geom = "density",colour=color) # 2.5 条形图(柱状图) #计数,求count(color) qplot(color, data = diamonds, geom = "bar") #加权,对每个求sum(carat),类似于excel里的数据透视图,按不同的color计算carat的总和 qplot(color, data = diamonds, geom = "bar", weight = carat) #2.6. Time-series qplot(date, unemploy / pop, data = economics, geom = "line") #2.7. Path plot #如果要查看失业率(unemploy / pop)与平均失业时间(uempmed)之间的关系,一个方法是利用散点图,但是这样做就会导致无法观察到随时间变化的趋势了,path plot利用颜色深浅来代表年份,随着颜色从浅蓝变成深蓝,可以观察到失业率与失业时间的关系的变化趋势。 #具体实现:先自定义函数year(),将字符串格式的时间转化为年 year <- function(x) as.POSIXlt(x)$year + 1900 #画出path plot,颜色按年份由浅到深 qplot(unemploy / pop, uempmed, data = economics, geom = "path", colour = year(date)) 我们已经讨论了如何利用外观参数在同一图中比较不同分类的差异。而分面可以将不同的亚类放在不同的图中进行比较: qplot(carat, data = diamonds, facets = color ~ .,geom = "histogram", binwidth = 0.1, xlim = c(0, 3)) qplot(carat, data = diamonds, facets = color ~ .,geom = "histogram", binwidth = 0.1, xlim = c(0, 3)) 下面的图形在一开始的基础上添加了新的元素:分面,多个图层以及统计数据。分面和图层扩展了上面提到的数据结构:每一个分面的每一个图层都有属于自己的数据集。你可以将它想象成是一个三维的数组:分面构成了二维平面,然后图层给予其在新的维度上的扩展。在这个例子中,不同图层上的数据是一样的,但是从理论上来讲,不同的图层中可以有不同的数据。 qplot(displ, hwy, data=mpg, facets = . ~ year) + geom_smooth() ggplot 基本绘图类型: 这些几何元素是ggplot的基础。他们彼此结合可以构成复杂的图像。他们中的绝大多数对应特定的绘图类型。 geom_area() geom_bar() geom_line() geom_point() geom_polygon() geom_text() geom_tile() > library("ggplot2") > head(mpg) manufacturer model displ year cyl trans drv cty 1 audi a4 1.8 1999 4 auto(l5) f 18 2 audi a4 1.8 1999 4 manual(m5) f 21 3 audi a4 2.0 2008 4 manual(m6) f 20 4 audi a4 2.0 2008 4 auto(av) f 21 5 audi a4 2.8 1999 6 auto(l5) f 16 6 audi a4 2.8 1999 6 manual(m5) f 18 hwy fl class 1 29 p compact 2 29 p compact 3 31 p compact 4 30 p compact 5 26 p compact 6 26 p compact > p <- ggplot(mpg, aes(x = cty, y = hwy, colour = factor(year))) > summary(p) data: manufacturer, model, displ, year, cyl, trans, drv, cty, hwy, fl, class [234x11] mapping: x = cty, y = hwy, colour = factor(year) faceting: facet_null() 然后就是几何对象和统计,简单的理解就是通过统计变换把前面的元素表现出来,因为统计变换的函数stat开头的默认有包含自己的几何图形,而几何图形函数geom又带有自己的统计变换,通常都能达到目的。 p + geom_point() #散点图 ggplot(mpg, aes(x = displ)) + geom_histogram(aes(y = (..count..)), fill = "steelblue", colour = "#808080", bin = 0.1) #直方图 ggplot(mpg, aes(y = displ, x = factor(cyl), fill = factor(cyl))) + geom_boxplot() #盒图 ggplot(diamonds, aes(carat, price)) + stat_bin2d() #二维密度图 p + geom_point() + stat_smooth(method = "lm", se = F) ggplot(mpg, aes(x = cty, y = hwy)) + geom_point(aes(colour = factor(year))) + stat_smooth(method = "lm", se = F) #请注意两种方式的区别 ggplot(mpg, aes(y = hwy, x = class, colour = class)) + geom_boxplot() + geom_jitter(alpha = 0.3) + theme(panel.grid = element_blank(), panel.background = element_rect(fill = NA, colour = "black")) ggplot(mpg, aes(x = displ)) + stat_bin(aes(y = ..density.., fill = factor(year)), colour = "#909090") + stat_density(aes(ymax = "density", colour = factor(year)), geom = "line", size = 1.2) + facet_wrap(~year, ncol = 1) ggplot2中的基本概念 将数据中变量映射到图形属性。映射控制了二者之间的关系。 标度:标度负责控制映射后图形属性的显示方式。具体形式上来看是图例和坐标刻度。scale和mapping是紧密相关的概念。 几何对象(Geometric):几何对象代表我们图中看到的图形元素,如点、线、多边形等。 统计变换(Statistics):对原始数据进行某种计算,例如二元散点上加上一条回归线。 坐标系统(Coordinate):坐标系统控制坐标轴并影响所有图形元素,坐标轴可以进行变换以满足不同的需要。 图层(Layer):数据、映射、几何对象、统计变换等构成一个图层。图层可以允许用户一步步的构建图形,方便单独对图层进行修改。 分面(Facet):条件绘图,将数据按某种方式分组,然后分别绘图。分面就是控制分组绘图的方法和排列形式。 总结 关于ggplot2的绘图功能还有待进一步挖掘。
文本挖掘的艺术之一: QQ聊天记录:中文聊天内容的挖掘 核心词云的制作: 在用R做文本挖掘之前我们需要做一些前期的环境准备, 我们这里做分析的文本是tm包下面的一个示例文本, 例如: 第一步:设置文本路径: setwd("C:\\Users\\aioger\\Documents\\R\\win-library\\3.2\\tm") 第二步:建立自己的语料库: ovid <- VCorpus(DirSource(txt, encoding= "UTF-8"), readerControl = list(language = "en")) 第三步:文档词项矩阵 dtm <- DocumentTermMatrix(reuters) #词频关联查找: findAssocs(dtm,"qui",0.3) 第四:删除关联词频少的 dtm1<- removeSparseTerms(dtm,sparse=0.5)#这里是把关联性小于0.5的词给删掉 第五步:转正 data1<-t(t(dtm1)) data1<-as.matrix(data1) data1<-t(data1) 对data1做中心化 data.scale <- scale(data1) 绘制聚类图 d <- dist(data.scale, method ="euclidean") fit <- hclust(d,method="ward.D") plot(fit,main ="文件聚类分析-王华") 下面我们在来画出这个的词云图 v<-sort(rowSums(data1),decreasing=TRUE) d<-data.frame(word=names(v),freq=v) wordcloud(d$word,d$freq) wordcloud(d$word,d$freq,scale = c(6, 1.5),min.freq = 2, max.words = 1000, colors = rainbow(100))
本挖掘典型地运用了机器学习技术,例如聚类,分类,关联规则,和预测建模。这些技术揭示潜在内容中的意义和关系。文本发掘应用于诸如竞争情报,生命科学,客户呼声,媒体和出版,法律和税收,法律实施,情感分析和趋势识别。 在本篇博客帖中,你将会学习到如何将机器学习技术应用到文本挖掘中。我将会向你展示如何使用RapidMiner(一款流行的预测分析开源工具)和亚马逊S3业务来创建一个文件挖掘应用。亚马逊S3业务是一项易用的存储服务,可使组织在网页上的任何地方存储和检索任意数量的数据。 掘模型产生的结果可以得到持续的推导并应用于解决特定问题 为什么使用文本挖掘技术? 文本挖掘技术帮助你在大量的肉眼不可见的文本内容中隐藏的文本模式和关系,带来了新的商机和进程的改进。使用文本挖掘技术可以节省你的时间和资源,因为文本挖掘进程可以实现自动化,文本挖掘模型产生的结果可以得到持续的推导并应用于解决特定问题。 这些技术可以帮助你: 从大量的文本内容中提取关键概念,文本模式和关系。 以主题(例如旅行和娱乐)为依据,在文本内容中识别各种趋势,以便理解用户情感。 从文档中概括内容,从语义上理解潜在内容。 索引和搜索文本以便在预测分析中使用。 正如你所看到的,除了事务性内容外,如果你不分析文本内容,你可能错失重大的机遇. 以前文本挖掘所面临的障碍 在过去,从大量的文本中提取有价值的透彻分析通常很难。提取有价值的透彻分析需要技艺精湛的IT人才来执行复杂的编程和建模任务。另外,在维持性能和创新周期所要求的速度和灵敏度的条件下,所具有的基础设施简直无法满足处理大量非结构化文本的要求。工具与潜在基础设施的集成则是面临的另一个挑战。这通常导致数据和工具从一个环境迁移到另一个环境。此外,商业用户发现很难解读这些结果。易于挖掘和分析的结构化数据变成大多数数据分析任务的主要数据源。结果是大量的文本内容实际上未被使用。 文本分析的新近发展 数据和云基础设施已经取得了巨大的进步。这包括机器学习和文本挖掘领域可用的各种工具和技术。伴随着这些发展,速度,创新和可扩展性现在变成了可能。在组织使用分析学方面也已经出现了根本性的转变:不是应对过去的趋势,组织通过根据当前事件预测未来趋势而变得主动。多亏了AWS提供的各种云基础设施服务和诸如RapidMiner,组织不再需要先进的编程技术就可以在可扩展和持久的环境中快速地分析文本内容了。RapidMiner工具综合了机器学习,文本挖掘和可视化能力。 文本挖掘流程 大多数文本挖掘遵循以下的典型流程: 1.识别和提取待分析的文档。应用结构化的,统计的和语言技术(通常是共同应用)来识别,标识和提取各种成分,例如实体,概念和关系。 2.应用统计学的模式匹配和相似性技术来将文档分类并根据特定的分组或分类组织提取出的特征。潜在的非结构化数据转化为易于分析的结构化数据。分类过程帮助识别含义和各种关系。 3.评估模型的性能。 4.向最终用户呈现分析结果。 下面的流程图说明了这一流程。 典型的文本挖掘流程图 第一行:识别/提取待分析的文本/文档 应用统计的/语言的/结构化技术来分析 推断含义/识别内容/应用词类分析法 第二行:提取概念和模式 应用统计的/机器学习/模式匹配技术 将文档分类,根据分类学组织文档 第三行:识别文本含义和大量文本中各种关系 评估模型性能,检查查准率/查全率/准确性/相关性 向最终用户呈现分析结果 机器学习在文本挖掘中的作用 典型地,文本挖掘技术根据因子(例如术语频率和分布)的统计分析建立一组重要的单词和句子。根据重要性,得分最高的单词和句子典型地表明潜在的观点,感情或一般主题。 作为过程的一部分,现代工具典型地构建一个文档术语矩阵(DTM),使用加权方法,如词频-逆文档频率法(TF-IDF)。这些工具提取并将潜在信息,如标准特征,关键词频率,文档和文本列表特征,以表格的形式存储在数据库中。可以查询这些表格进行系数分析和处理。这些步骤是将机器学习技术应用到文本内容的前导。 文本分析学典型地运用机器学习技术,如聚类,分类,关联规则和预测建模来识别潜在内容中的含义和各种关系。然后使用各种方法处理非机构化数据源中包含的潜在文本。非结构化数据源包括自然语言处理(NLP),语法分析,标记化(明显成分的识别,如单词和N个字尾),词干提取(将单词变体缩减为词干),术语归约(使用同义词和相似度量的小组类术语)和词类标记。这些数据源帮助识别事实和关系。 文本分析另一个关键的方面涉及组织和构建潜在的文本内容。典型的技术包括聚类,编目,分类和归类。很多工具使用的典型的分类方法包括朴素贝叶斯,支持向量机和K最近邻分类算法。 下面的表格包含了常用的文本挖掘技术,包括机器学习和每一种技术的考虑因素。 文本挖掘技术 关键的考虑因素 一旦使用以上的技术对文本进行了处理,分组和分析,评价结果就变得很重要。评估的目的是确定你是否已经找到了最相关的材料或是否你丢失了一些重要术语。你将会使用查准率和查全率和评估结果。 使用AWS服务和RapidMiner进行情感分析 现在让我们看一下你如何使用AWS服务和RapidMiner进行情感分析,这是文本挖掘一个很普遍的应用案例。在情感分析中,你识别积极和消极的观点,情绪和评价,经常使用机器学习技术分析文本内容。使用AWS和RapidMiner,你不用将非结构化数据迁移到另一个环境中就可以使用情感分析这样的技术对存储在S3中的数据直接进行分析。 如下所示,你可以使用RapidMiner创建文本挖掘流程与S3进行集成。S3上的一个对象可能是任何一种文件,也可能是任何一种格式,如文本文件,招聘,或视频。这使得S3在存储文本挖掘和先进的分析学所需的非结构化数据方面变得非常有用。 亚马逊S3服务与其他的亚马逊大数据服务,如Amazon Redshift,Amazon RDS,AmazonDynamoDB, Amazon Kinesis和Amazon EMR,是集成的。这就产生了在AWS中使用RapidMiner开发文本挖掘模型的有趣场景。例如,你可以使用S3服务来存储从这些亚马逊业务中提取的数据,然后使用RapidMiner对这些数据快速构建一个文本挖掘模型。你可以将模型输出的结果存储到你选择的S3桶和区域中并将这些结果和更广泛的最终用户社区分享。 下面的举例使用加利福尼亚大学尔湾分校主办的SMS Spam collection(垃圾短信收集)数据组。SMS Spam collection是由一组为手机垃圾的研究而收集的标签消息组成的。这个数据组综合了垃圾和非垃圾短信(标记为ham)。这一数据组每行一条短信,使用UTF-8编码,以制表符为分隔,构成一个文本文件。 视频演示 下面的视频样本将会向你展示如何使用RapidMiner和S3进行文本挖掘。注意:视频样本没有声音。 开始前,请: 1.下载并安装RapidMiner软件和可从RapidMiner Marketplace获取的RapidMiner Text Processing Extension。你可以将RapidMiner安装在你的本地电脑上。如果你当前的电脑配置不能提供足够的容量,也可以将RapidMiner安装在亚马逊EC2实例上。 2.使用你的AWS证书在RapidMiner配置S3连接信息。要使用S3服务,你需要有一个AWS账户。 3.将文本挖掘案例研究所需输入数据组上传到S3桶中。 从S3中导入和读取数据到RapidMiner 下面的视频将会向你展示如何使用你上传到S3桶中的数据,S3服务和RapidMiner创建一个文本挖掘应用。记住:你必须导入使用UTF-8编码的文件,确定制表符为分隔符以便以正确的格式来处理文件。 视频:从S3中导入和读取数据到RapidMiner https://s3.amazonaws.com/awsbigdatablog/1-AmazonS3-RapidMiner-Text-Mining-Video.mp4 使用RapidMiner’s Validation运算符 当对不可见的数据运行模型时,你看到的准确性可能低于预期。这是可能的,因为我们使用的方法可能已经学习了它所看到的数据,但是从未针对不可见的数据对该方法进行测试。为了解决这一问题,你可以使用下面的视频中所示的RapidMiner Validation运算符。 视频:使用RapidMiner’s Validation运算符 http://s3.amazonaws.com/awsbigdatablog/2-AmazonS3-RapidMiner-Text-Mining-Video.mp4 在RapidMiner中应用Store运算符 为了将已经学习到的模型应用到新数据,你必须将模型和单词表存储到RapidMiner仓库。你必须存储单词表是因为当你预测一个新消息是垃圾短信还是非垃圾短信的概率时,你不得不使用原来的过程中使用的相同的属性或单词。因此,你需要相同的单词表和模型,需要以你处理正在学习的数据时使用的方式来处理新数据。下面的视频展示了这是如何做到的。 视频:在RapidMiner中应用Store运算符 https://s3.amazonaws.com/awsbigdatablog/3-AmazonS3-RapidMiner-Text-Mining-Video.mp4 将不可见的数据应用到RapidMiner模型 下面的视频展示了如何应用你使用Retrieve运算符为新的不可见数据构建的模型来预测新消息是非垃圾短信还是垃圾短信。 视频:将不可见的数据应用到RapidMiner模型 https://s3.amazonaws.com/awsbigdatablog/4-AmazonS3-RapidMiner-Text-Mining-Video.mp4 使用Write S3运算符存储结果 下面的视频展示了如何在RapidMiner中使用Write S3运算符将输出结果存储到S3桶中,该桶已经在前面的概述中被设置为RapidMiner的一个连接。你可以从特定的S3桶中将输出结果下载到本地,使用文本编辑器查看这些结果。 视频:使用Write S3运算符存储结果 https://s3.amazonaws.com/awsbigdatablog/5-AmazonS3-RapidMiner-Text-Mining-Video.mp4
什么是熵(Entropy) 简单来说,熵是表示物质系统状态的一种度量,用它老表征系统的无序程度。熵越大,系统越无序,意味着系统结构和运动的不确定和无规则;反之,,熵越小,系统越有序,意味着具有确定和有规则的运动状态。熵的中文意思是热量被温度除的商。负熵是物质系统有序化,组织化,复杂化状态的一种度量。 熵最早来原于物理学. 德国物理学家鲁道夫·克劳修斯首次提出熵的概念,用来表示任何一种能量在空间中分布的均匀程度,能量分布得越均匀,熵就越大。 一滴墨水滴在清水中,部成了一杯淡蓝色溶液 热水晾在空气中,热量会传到空气中,最后使得温度一致 更多的一些生活中的例子: 熵力的一个例子是耳机线,我们将耳机线整理好放进口袋,下次再拿出来已经乱了。让耳机线乱掉的看不见的“力”就是熵力,耳机线喜欢变成更混乱。 熵力另一个具体的例子是弹性力。一根弹簧的力,就是熵力。 胡克定律其实也是一种熵力的表现。 万有引力也是熵力的一种(热烈讨论的话题)。 浑水澄清[1] 于是从微观看,熵就表现了这个系统所处状态的不确定性程度。香农,描述一个信息系统的时候就借用了熵的概念,这里熵表示的是这个信息系统的平均信息量(平均不确定程度)。 最大熵模型 我们在投资时常常讲不要把所有的鸡蛋放在一个篮子里,这样可以降低风险。在信息处理中,这个原理同样适用。在数学上,这个原理称为最大熵原理(the maximum entropy principle)。 让我们看一个拼音转汉字的简单的例子。假如输入的拼音是"wang-xiao-bo",利用语言模型,根据有限的上下文(比如前两个词),我们能给出两个最常见的名字“王小波”和“王晓波 ”。至于要唯一确定是哪个名字就难了,即使利用较长的上下文也做不到。当然,我们知道如果通篇文章是介绍文学的,作家王小波的可能性就较大;而在讨论两岸关系时,台湾学者王晓波的可能性会较大。在上面的例子中,我们只需要综合两类不同的信息,即主题信息和上下文信息。虽然有不少凑合的办法,比如:分成成千上万种的不同的主题单独处理,或者对每种信息的作用加权平均等等,但都不能准确而圆满地解决问题,这样好比以前我们谈到的行星运动模型中的小圆套大圆打补丁的方法。在很多应用中,我们需要综合几十甚至上百种不同的信息,这种小圆套大圆的方法显然行不通。 数学上最漂亮的办法是最大熵(maximum entropy)模型,它相当于行星运动的椭圆模型。“最大熵”这个名词听起来很深奥,但是它的原理很简单,我们每天都在用。说白了,就是要保留全部的不确定性,将风险降到最小。 回到我们刚才谈到的拼音转汉字的例子,我们已知两种信息,第一,根据语言模型,wangxiao-bo可以被转换成王晓波和王小波;第二,根据主题,王小波是作家,《黄金时代》的作者等等,而王晓波是台湾研究两岸关系的学者。因此,我们就可以建立一个最大熵模型,同时满足这两种信息。现在的问题是,这样一个模型是否存在。匈牙利著名数学家、信息论最高奖香农奖得主希萨(Csiszar)证明,对任何一组不自相矛盾的信息,这个最大熵模型不仅存在,而且是唯一的。而且它们都有同一个非常简单的形式 — 指数函数。下面公式是根据上下文(前两个词)和主题预测下一个词的最大熵模型,其中 w3 是要预测的词(王晓波或者王小波)w1 和 w2 是它的前两个字(比如说它们分别是“出版”,和“”),也就是其上下文的一个大致估计,subject 表示主题。 我们看到,在上面的公式中,有几个参数 lambda 和 Z ,他们需要通过观测数据训练出来。最大熵模型在形式上是最漂亮的统计模型,而在实现上是最复杂的模型之一。 我们上次谈到用最大熵模型可以将各种信息综合在一起。我们留下一个问题没有回答,就是如何构造最大熵模型。我们已经所有的最大熵模型都是指数函数的形式,现在只需要确定指数函数的参数就可以了,这个过程称为模型的训练。 最原始的最大熵模型的训练方法是一种称为通用迭代算法 GIS(generalized iterative scaling) 的迭代 算法。GIS 的原理并不复杂,大致可以概括为以下几个步骤: 1. 假定第零次迭代的初始模型为等概率的均匀分布。 2. 用第 N 次迭代的模型来估算每种信息特征在训练数据中的分布,如果超过了实际的,就把相应的模型参数变小;否则,将它们便大。 3. 重复步骤 2 直到收敛。 GIS 最早是由 Darroch 和 Ratcliff 在七十年代提出的。但是,这两人没有能对这种算法的物理含义进行很好地解释。后来是由数学家希萨(Csiszar)解释清楚的,因此,人们在谈到这个算法时,总是同时引用 Darroch 和Ratcliff 以及希萨的两篇论文。GIS 算法每次迭代的时间都很长,需要迭代很多次才能收敛,而且不太稳定,即使在 64 位计算机上都会出现溢出。因此,在实际应用中很少有人真正使用 GIS。大家只是通过它来了解最大熵模型的算法。 八十年代,很有天才的孪生兄弟的达拉皮垂(Della Pietra)在 IBM 对 GIS 算法进行了两方面的改进,提出了改进迭代算法 IIS(improved iterative scaling)。这使得最大熵模型的训练时间缩短了一到两个数量级。这样最大熵模型才有可能变得实用。即使如此,在当时也只有 IBM 有条件是用最大熵模型。 由于最大熵模型在数学上十分完美,对科学家们有很大的诱惑力,因此不少研究者试图把自己的问题用一个类似最大熵的近似模型去套。谁知这一近似,最大熵模型就变得不完美了,结果可想而知,比打补丁的凑合的方法也好不了多少。于是,不少热心人又放弃了这种方法。第一个在实际信息处理应用中验证了最大熵模型的优势的,是宾夕法尼亚大学马库斯的另一个高徒原 IBM 现微软的研究员拉纳帕提(Adwait Ratnaparkhi)。拉纳帕提的聪明之处在于他没有对最大熵模型进行近似,而是找到了几个最适合用最大熵模型、而计算量相对不太大的自然语言处理问题,比如词性标注和句法分析。拉纳帕提成功地将上下文信息、词性(名词、动词和形容词等)、句子成分(主谓宾)通过最大熵模型结合起来,做出了当时世界上最好的词性标识系统和句法分析器。拉纳帕提的论文发表后让人们耳目一新。拉纳帕提的词性标注系统,至今仍然是使用单一方法最好的系统。科学家们从拉纳帕提的成就中,又看到了用最大熵模型解决复杂的文字信息处理的希望。 但是,最大熵模型的计算量仍然是个拦路虎。我在学校时花了很长时间考虑如何简化最大熵模型的计算量。终于有一天,我对我的导师说,我发现一种数学变换,可以将大部分最大熵模型的训练时间在 IIS 的基础上减少两个数量级。我在黑板上推导了一个多小时,他没有找出我的推导中的任何破绽,接着他又回去想了两天,然后告诉我我的算法是对的。从此,我们就建造了一些很大的最大熵模型。这些模型比修修补补的凑合的方法好不少。即使在我找到了快速训练算法以后,为了训练一个包含上下文信息,主题信息和语法信息的文法模型(language model),我并行使用了20 台当时最快的 SUN 工作站,仍然计算了三个月。由此可见最大熵模型的复杂的一面。 最大熵模型,可以说是集简与繁于一体,形式简单,实现复杂。值得一提的是,在Google的很多产品中,比如机器翻译,都直接或间接地用到了最大熵模型。 讲到这里,读者也许会问,当年最早改进最大熵模型算法的达拉皮垂兄弟这些年难道没有做任何事吗?他们在九十年代初贾里尼克离开 IBM 后,也退出了学术界,而到在金融界大显身手。他们两人和很多 IBM 语音识别的同事一同到了一家当时还不大,但现在是世界上最成功对冲基金(hedge fund)公司—-文艺复兴技术公司 (Renaissance Technologies)。我们知道,决定股票涨落的因素可能有几十甚至上百种,而最大熵方法恰恰能找到一个同时满足成千上万种不同条件的模型。达拉皮垂兄弟等科学家在那里,用于最大熵模型和其他一些先进的数学工具对股票预测,获得了巨大的成功。从该基金 1988 年创立至今,它的净回报率高达平均每年 34%。也就是说,如果 1988 年你在该基金投入一块钱,今天你能得到 200 块钱。这个业绩,远远超过股神巴菲特的旗舰公司伯克夏哈撒韦(Berkshire Hathaway)。同期,伯克夏哈撒韦的总回报是 16 倍。 值得一提的是,信息处理的很多数学手段,包括隐含马尔可夫模型、子波变换、贝叶斯网络等等,在华尔街多有直接的应用。由此可见,数学模型的作用。 HMM(隐马尔可夫模型) 隐马尔可夫模型(Hidden Markov Model,HMM)是统计模型,它用来描述一个含有隐含未知参数的马尔可夫过程。其难点是从可观察的参数中确定该过程的隐含参数。然后利用这些参数来作进一步的分析,例如模式识别。 是在被建模的系统被认为是一个马尔可夫过程与未观测到的(隐藏的)的状态的统计马尔可夫模型。 下面用一个简单的例子来阐述: 假设我手里有三个不同的骰子。第一个骰子是我们平常见的骰子(称这个骰子为D6),6个面,每个面(1,2,3,4,5,6)出现的概率是1/6。第二个骰子是个四面体(称这个骰子为D4),每个面(1,2,3,4)出现的概率是1/4。第三个骰子有八个面(称这个骰子为D8),每个面(1,2,3,4,5,6,7,8)出现的概率是1/8。 假设我们开始掷骰子,我们先从三个骰子里挑一个,挑到每一个骰子的概率都是1/3。然后我们掷骰子,得到一个数字,1,2,3,4,5,6,7,8中的一个。不停的重复上述过程,我们会得到一串数字,每个数字都是1,2,3,4,5,6,7,8中的一个。例如我们可能得到这么一串数字(掷骰子10次):1 6 3 5 2 7 3 5 2 4 这串数字叫做可见状态链。但是在隐马尔可夫模型中,我们不仅仅有这么一串可见状态链,还有一串隐含状态链。在这个例子里,这串隐含状态链就是你用的骰子的序列。比如,隐含状态链有可能是:D6 D8 D8 D6 D4 D8 D6 D6 D4 D8 一般来说,HMM中说到的马尔可夫链其实是指隐含状态链,因为隐含状态(骰子)之间存在转换概率(transition probability)。在我们这个例子里,D6的下一个状态是D4,D6,D8的概率都是1/3。D4,D8的下一个状态是D4,D6,D8的转换概率也都一样是1/3。这样设定是为了最开始容易说清楚,但是我们其实是可以随意设定转换概率的。比如,我们可以这样定义,D6后面不能接D4,D6后面是D6的概率是0.9,是D8的概率是0.1。这样就是一个新的HMM。 同样的,尽管可见状态之间没有转换概率,但是隐含状态和可见状态之间有一个概率叫做输出概率(emission probability)。就我们的例子来说,六面骰(D6)产生1的输出概率是1/6。产生2,3,4,5,6的概率也都是1/6。我们同样可以对输出概率进行其他定义。比如,我有一个被赌场动过手脚的六面骰子,掷出来是1的概率更大,是1/2,掷出来是2,3,4,5,6的概率是1/10。 其实对于HMM来说,如果提前知道所有隐含状态之间的转换概率和所有隐含状态到所有可见状态之间的输出概率,做模拟是相当容易的。但是应用HMM模型时候呢,往往是缺失了一部分信息的,有时候你知道骰子有几种,每种骰子是什么,但是不知道掷出来的骰子序列;有时候你只是看到了很多次掷骰子的结果,剩下的什么都不知道。如果应用算法去估计这些缺失的信息,就成了一个很重要的问题。这些算法我会在下面详细讲。 ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× 如果你只想看一个简单易懂的例子,就不需要往下看了。 ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× 说两句废话,答主认为呢,要了解一个算法,要做到以下两点:会其意,知其形。答主回答的,其实主要是第一点。但是这一点呢,恰恰是最重要,而且很多书上不会讲的。正如你在追一个姑娘,姑娘对你说“你什么都没做错!”你要是只看姑娘的表达形式呢,认为自己什么都没做错,显然就理解错了。你要理会姑娘的意思,“你赶紧给我道歉!”这样当你看到对应的表达形式呢,赶紧认错,跪地求饶就对了。数学也是一样,你要是不理解意思,光看公式,往往一头雾水。不过呢,数学的表达顶多也就是晦涩了点,姑娘的表达呢,有的时候就完全和本意相反。所以答主一直认为理解姑娘比理解数学难多了。 回到正题,和HMM模型相关的算法主要分为三类,分别解决三种问题: 1)知道骰子有几种(隐含状态数量),每种骰子是什么(转换概率),根据掷骰子掷出的结果(可见状态链),我想知道每次掷出来的都是哪种骰子(隐含状态链)。 这个问题呢,在语音识别领域呢,叫做解码问题。这个问题其实有两种解法,会给出两个不同的答案。每个答案都对,只不过这些答案的意义不一样。第一种解法求最大似然状态路径,说通俗点呢,就是我求一串骰子序列,这串骰子序列产生观测结果的概率最大。第二种解法呢,就不是求一组骰子序列了,而是求每次掷出的骰子分别是某种骰子的概率。比如说我看到结果后,我可以求得第一次掷骰子是D4的概率是0.5,D6的概率是0.3,D8的概率是0.2.第一种解法我会在下面说到,但是第二种解法我就不写在这里了,如果大家有兴趣,我们另开一个问题继续写吧。 2)还是知道骰子有几种(隐含状态数量),每种骰子是什么(转换概率),根据掷骰子掷出的结果(可见状态链),我想知道掷出这个结果的概率。 看似这个问题意义不大,因为你掷出来的结果很多时候都对应了一个比较大的概率。问这个问题的目的呢,其实是检测观察到的结果和已知的模型是否吻合。如果很多次结果都对应了比较小的概率,那么就说明我们已知的模型很有可能是错的,有人偷偷把我们的骰子給换了。 3)知道骰子有几种(隐含状态数量),不知道每种骰子是什么(转换概率),观测到很多次掷骰子的结果(可见状态链),我想反推出每种骰子是什么(转换概率)。 这个问题很重要,因为这是最常见的情况。很多时候我们只有可见结果,不知道HMM模型里的参数,我们需要从可见结果估计出这些参数,这是建模的一个必要步骤。 问题阐述完了,下面就开始说解法。(0号问题在上面没有提,只是作为解决上述问题的一个辅助) 0.一个简单问题 其实这个问题实用价值不高。由于对下面较难的问题有帮助,所以先在这里提一下。 知道骰子有几种,每种骰子是什么,每次掷的都是什么骰子,根据掷骰子掷出的结果,求产生这个结果的概率。 解法无非就是概率相乘: 1.看见不可见的,破解骰子序列 这里我说的是第一种解法,解最大似然路径问题。 举例来说,我知道我有三个骰子,六面骰,四面骰,八面骰。我也知道我掷了十次的结果(1 6 3 5 2 7 3 5 2 4),我不知道每次用了那种骰子,我想知道最有可能的骰子序列。 其实最简单而暴力的方法就是穷举所有可能的骰子序列,然后依照第零个问题的解法把每个序列对应的概率算出来。然后我们从里面把对应最大概率的序列挑出来就行了。如果马尔可夫链不长,当然可行。如果长的话,穷举的数量太大,就很难完成了。 另外一种很有名的算法叫做Viterbi algorithm. 要理解这个算法,我们先看几个简单的列子。 首先,如果我们只掷一次骰子: 看到结果为1.对应的最大概率骰子序列就是D4,因为D4产生1的概率是1/4,高于1/6和1/8. 把这个情况拓展,我们掷两次骰子: 结果为1,6.这时问题变得复杂起来,我们要计算三个值,分别是第二个骰子是D6,D4,D8的最大概率。显然,要取到最大概率,第一个骰子必须为D4。这时,第二个骰子取到D6的最大概率是 同样的,我们可以计算第二个骰子是D4或D8时的最大概率。我们发现,第二个骰子取到D6的概率最大。而使这个概率最大时,第一个骰子为D4。所以最大概率骰子序列就是D4 D6。 继续拓展,我们掷三次骰子: 同样,我们计算第三个骰子分别是D6,D4,D8的最大概率。我们再次发现,要取到最大概率,第二个骰子必须为D6。这时,第三个骰子取到D4的最大概率是 同上,我们可以计算第三个骰子是D6或D8时的最大概率。我们发现,第三个骰子取到D4的概率最大。而使这个概率最大时,第二个骰子为D6,第一个骰子为D4。所以最大概率骰子序列就是D4 D6 D4。 写到这里,大家应该看出点规律了。既然掷骰子一二三次可以算,掷多少次都可以以此类推。我们发现,我们要求最大概率骰子序列时要做这么几件事情。首先,不管序列多长,要从序列长度为1算起,算序列长度为1时取到每个骰子的最大概率。然后,逐渐增加长度,每增加一次长度,重新算一遍在这个长度下最后一个位置取到每个骰子的最大概率。因为上一个长度下的取到每个骰子的最大概率都算过了,重新计算的话其实不难。当我们算到最后一位时,就知道最后一位是哪个骰子的概率最大了。然后,我们要把对应这个最大概率的序列从后往前推出来。 2.谁动了我的骰子? 比如说你怀疑自己的六面骰被赌场动过手脚了,有可能被换成另一种六面骰,这种六面骰掷出来是1的概率更大,是1/2,掷出来是2,3,4,5,6的概率是1/10。你怎么办么?答案很简单,算一算正常的三个骰子掷出一段序列的概率,再算一算不正常的六面骰和另外两个正常骰子掷出这段序列的概率。如果前者比后者小,你就要小心了。 比如说掷骰子的结果是: 要算用正常的三个骰子掷出这个结果的概率,其实就是将所有可能情况的概率进行加和计算。同样,简单而暴力的方法就是把穷举所有的骰子序列,还是计算每个骰子序列对应的概率,但是这回,我们不挑最大值了,而是把所有算出来的概率相加,得到的总概率就是我们要求的结果。这个方法依然不能应用于太长的骰子序列(马尔可夫链)。 我们会应用一个和前一个问题类似的解法,只不过前一个问题关心的是概率最大值,这个问题关心的是概率之和。解决这个问题的算法叫做前向算法(forward algorithm)。 首先,如果我们只掷一次骰子: 看到结果为1.产生这个结果的总概率可以按照如下计算,总概率为0.18: 把这个情况拓展,我们掷两次骰子: 看到结果为1,6.产生这个结果的总概率可以按照如下计算,总概率为0.05: 继续拓展,我们掷三次骰子: 看到结果为1,6,3.产生这个结果的总概率可以按照如下计算,总概率为0.03: 同样的,我们一步一步的算,有多长算多长,再长的马尔可夫链总能算出来的。用同样的方法,也可以算出不正常的六面骰和另外两个正常骰子掷出这段序列的概率,然后我们比较一下这两个概率大小,就能知道你的骰子是不是被人换了。 Viterbi algorithm HMM(隐马尔可夫模型)是用来描述隐含未知参数的统计模型,举一个经典的例子:一个东京的朋友每天根据天气{下雨,天晴}决定当天的活动{公园散步,购物,清理房间}中的一种,我每天只能在twitter上看到她发的推“啊,我前天公园散步、昨天购物、今天清理房间了!”,那么我可以根据她发的推特推断东京这三天的天气。在这个例子里,显状态是活动,隐状态是天气。 任何一个HMM都可以通过下列五元组来描述: :param obs:观测序列 :param states:隐状态 :param start_p:初始概率(隐状态) :param trans_p:转移概率(隐状态) :param emit_p: 发射概率 (隐状态表现为显状态的概率) 伪码如下: states = ('Rainy', 'Sunny') observations = ('walk', 'shop', 'clean') start_probability = {'Rainy': 0.6, 'Sunny': 0.4} transition_probability = { 'Rainy' : {'Rainy': 0.7, 'Sunny': 0.3}, 'Sunny' : {'Rainy': 0.4, 'Sunny': 0.6}, } emission_probability = { 'Rainy' : {'walk': 0.1, 'shop': 0.4, 'clean': 0.5}, 'Sunny' : {'walk': 0.6, 'shop': 0.3, 'clean': 0.1}, } 求解最可能的天气 求解最可能的隐状态序列是HMM的三个典型问题之一,通常用维特比算法解决。维特比算法就是求解HMM上的最短路径(-log(prob),也即是最大概率)的算法。 稍微用中文讲讲思路,很明显,第一天天晴还是下雨可以算出来: 定义V[时间][今天天气] = 概率,注意今天天气指的是,前几天的天气都确定下来了(概率最大)今天天气是X的概率,这里的概率就是一个累乘的概率了。 因为第一天我的朋友去散步了,所以第一天下雨的概率V[第一天][下雨] = 初始概率[下雨] * 发射概率[下雨][散步] = 0.6 * 0.1 = 0.06,同理可得V[第一天][天晴] = 0.24 。从直觉上来看,因为第一天朋友出门了,她一般喜欢在天晴的时候散步,所以第一天天晴的概率比较大,数字与直觉统一了。 从第二天开始,对于每种天气Y,都有前一天天气是X的概率 * X转移到Y的概率 * Y天气下朋友进行这天这种活动的概率。因为前一天天气X有两种可能,所以Y的概率有两个,选取其中较大一个作为V[第二天][天气Y]的概率,同时将今天的天气加入到结果序列中 比较V[最后一天][下雨]和[最后一天][天晴]的概率,找出较大的哪一个对应的序列,就是最终结果。 算法的代码可以在github上看到,地址为: https://github.com/hankcs/Viterbi 运行完成后根据Viterbi得到结果: Sunny Rainy Rainy Viterbi被广泛应用到分词,词性标注等应用场景。
伪分布式 hadoop的三种安装方式: Local (Standalone) Mode Pseudo-Distributed Mode Fully-Distributed Mode 安装之前需要 $ sudo apt-get install ssh $ sudo apt-get install rsync 详见:http://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-common/SingleCluster.html 伪分布式配置 Configuration 修改下边: etc/hadoop/core-site.xml: <configuration> <property> <name>fs.defaultFS</name> <value>hdfs://localhost:9000</value> </property> </configuration> etc/hadoop/hdfs-site.xml: <configuration> <property> <name>dfs.replication</name> <value>1</value> </property> </configuration> 配置ssh $ ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa $ cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys 如果想运行在yarn上 需要执行下边的步骤: Configure parameters as follows: etc/hadoop/mapred-site.xml: <configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> </configuration> etc/hadoop/yarn-site.xml: <configuration> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> </configuration> Start ResourceManager daemon and NodeManager daemon: $ sbin/start-yarn.sh Browse the web interface for the ResourceManager; by default it is available at: ResourceManager – http://localhost:8088/ Run a MapReduce job. When you’re done, stop the daemons with: $ sbin/stop-yarn.sh 输入: http://localhost:8088/ 可以看到 启动yarn后 Format the filesystem: $ bin/hdfs namenode -format Start NameNode daemon and DataNode daemon: $ sbin/start-dfs.sh The hadoop daemon log output is written to the $HADOOP_LOG_DIR directory (defaults to$HADOOP_HOME/logs). Browse the web interface for the NameNode; by default it is available at: NameNode – http://localhost:50070/ 输入后得到: 然后执行测试 Make the HDFS directories required to execute MapReduce jobs: $ bin/hdfs dfs -mkdir /user $ bin/hdfs dfs -mkdir /user/<username> Copy the input files into the distributed filesystem: $ bin/hdfs dfs -put etc/hadoop input Run some of the examples provided: $ bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.6.0.jar grep input output 'dfs[a-z.]+' Examine the output files: Copy the output files from the distributed filesystem to the local filesystem and examine them: $ bin/hdfs dfs -get output output $ cat output/* or View the output files on the distributed filesystem: $ bin/hdfs dfs -cat output/* 看运行的情况: 查看结果 测试执行成功,可以编写本地代码了。 eclipse hadoop2.6插件使用 下载源码: git clone https://github.com/winghc/hadoop2x-eclipse-plugin.git 下载过程: 编译插件: cd src/contrib/eclipse-plugin ant jar -Dversion=2.6.0 -Declipse.home=/usr/local/eclipse -Dhadoop.home=/usr/local/hadoop-2.6.0 //路径根据自己的配置 复制编译好的jar到eclipse插件目录,重启eclipse 配置 hadoop 安装目录 window ->preference -> hadoop Map/Reduce -> Hadoop installation directory 配置Map/Reduce 视图 window ->Open Perspective -> other->Map/Reduce -> 点击“OK” windows → show view → other->Map/Reduce Locations-> 点击“OK” 控制台会多出一个“Map/Reduce Locations”的Tab页 在“Map/Reduce Locations” Tab页 点击图标<大象+>或者在空白的地方右键,选择“New Hadoop location…”,弹出对话框“New hadoop location…”,配置如下内容:将ha1改为自己的hadoop用户 注意:MR Master和DFS Master配置必须和mapred-site.xml和core-site.xml等配置文件一致。 打开Project Explorer,查看HDFS文件系统。 新建Map/Reduce任务 File->New->project->Map/Reduce Project->Next 编写WordCount类:记得先把服务都起来 /** * */ package com.zongtui; /** * ClassName: WordCount <br/> * Function: TODO ADD FUNCTION. <br/> * date: Jun 28, 2015 5:34:18 AM <br/> * * @author zhangfeng * @version * @since JDK 1.7 */ import java.io.IOException; import java.util.Iterator; import java.util.StringTokenizer; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapred.FileInputFormat; import org.apache.hadoop.mapred.FileOutputFormat; import org.apache.hadoop.mapred.JobClient; import org.apache.hadoop.mapred.JobConf; import org.apache.hadoop.mapred.MapReduceBase; import org.apache.hadoop.mapred.Mapper; import org.apache.hadoop.mapred.OutputCollector; import org.apache.hadoop.mapred.Reducer; import org.apache.hadoop.mapred.Reporter; import org.apache.hadoop.mapred.TextInputFormat; import org.apache.hadoop.mapred.TextOutputFormat; public class WordCount { public static class Map extends MapReduceBase implements Mapper<LongWritable, Text, Text, IntWritable> { private final static IntWritable one = new IntWritable(1); private Text word = new Text(); public void map(LongWritable key, Text value, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException { String line = value.toString(); StringTokenizer tokenizer = new StringTokenizer(line); while (tokenizer.hasMoreTokens()) { word.set(tokenizer.nextToken()); output.collect(word, one); } } } public static class Reduce extends MapReduceBase implements Reducer<Text, IntWritable, Text, IntWritable> { public void reduce(Text key, Iterator<IntWritable> values, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException { int sum = 0; while (values.hasNext()) { sum += values.next().get(); } output.collect(key, new IntWritable(sum)); } } public static void main(String[] args) throws Exception { JobConf conf = new JobConf(WordCount.class); conf.setJobName("wordcount"); conf.setOutputKeyClass(Text.class); conf.setOutputValueClass(IntWritable.class); conf.setMapperClass(Map.class); conf.setReducerClass(Reduce.class); conf.setInputFormat(TextInputFormat.class); conf.setOutputFormat(TextOutputFormat.class); FileInputFormat.setInputPaths(conf, new Path(args[0])); FileOutputFormat.setOutputPath(conf, new Path(args[1])); JobClient.runJob(conf); } } user/admin123/input/hadoop是你上传在hdfs的文件夹(自己创建),里面放要处理的文件。ouput1放输出结果 将程序放在hadoop集群上运行:右键–>Runas –>Run on Hadoop,最终的输出结果会在HDFS相应的文件夹下显示。至此,ubuntu下hadoop-2.6.0 eclipse插件配置完成。 遇到异常 Exception in thread "main" org.apache.hadoop.mapred.FileAlreadyExistsException: Output directory hdfs://localhost:9000/output already exists at org.apache.hadoop.mapred.FileOutputFormat.checkOutputSpecs(FileOutputFormat.java:132) at org.apache.hadoop.mapreduce.JobSubmitter.checkSpecs(JobSubmitter.java:564) at org.apache.hadoop.mapreduce.JobSubmitter.submitJobInternal(JobSubmitter.java:432) at org.apache.hadoop.mapreduce.Job$10.run(Job.java:1296) at org.apache.hadoop.mapreduce.Job$10.run(Job.java:1293) at java.security.AccessController.doPrivileged(Native Method) at javax.security.auth.Subject.doAs(Subject.java:415) at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1628) at org.apache.hadoop.mapreduce.Job.submit(Job.java:1293) at org.apache.hadoop.mapred.JobClient$1.run(JobClient.java:562) at org.apache.hadoop.mapred.JobClient$1.run(JobClient.java:557) at java.security.AccessController.doPrivileged(Native Method) at javax.security.auth.Subject.doAs(Subject.java:415) at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1628) at org.apache.hadoop.mapred.JobClient.submitJobInternal(JobClient.java:557) at org.apache.hadoop.mapred.JobClient.submitJob(JobClient.java:548) at org.apache.hadoop.mapred.JobClient.runJob(JobClient.java:833) at com.zongtui.WordCount.main(WordCount.java:83) 1、改变输出路径。 2、删除重新建。 运行完成后看结果:
分类 分布式网络爬虫包含多个爬虫,每个爬虫需要完成的任务和单个的爬行器类似,它们从互联网上下载网页,并把网页保存在本地的磁盘,从中抽取URL并沿着这些URL的指向继续爬行。由于并行爬行器需要分割下载任务,可能爬虫会将自己抽取的URL发送给其他爬虫。这些爬虫可能分布在同一个局域网之中,或者分散在不同的地理位置。 根据爬虫的分散程度不同,可以把分布式爬行器分成以下两大类: 1、基于局域网分布式网络爬虫:这种分布式爬行器的所有爬虫在同一个局域网里运行,通过高速的网络连接相互通信。这些爬虫通过同一个网络去访问外部互联网,下载网页,所有的网络负载都集中在他们所在的那个局域网的出口上。由于局域网的带宽较高,爬虫之间的通信的效率能够得到保证;但是网络出口的总带宽上限是固定的,爬虫的数量会受到局域网出口带宽的限制。 2、基于广域网分布式网络爬虫:当并行爬行器的爬虫分别运行在不同地理位置(或网络位置),我们称这种并行爬行器为分布式爬行器。例如,分布式爬行器的爬虫可能位于中国,日本,和美国,分别负责下载这三地的网页;或者位于CHINANET,CERNET,CEINET,分别负责下载这三个网络的中的网页。分布式爬行器的优势在于可以子在一定程度上分散网络流量,减小网络出口的负载。如果爬虫分布在不同的地理位置(或网络位置),需要间隔多长时间进行一次相互通信就成为了一个值得考虑的问题。爬虫之间的通讯带宽可能是有限的,通常需要通过互联网进行通信。 大型分布式网络爬虫体系结构图 分布式网络爬虫是一项十分复杂系统。需要考虑很多方面因素。性能可以说是它这重要的指标。当然硬件层面的资源也是必须的。 架构 下面是项目的总体架构,第一个版本基于此方案来做。 上面的web层包括:控制台、基本权限、监控展示等,还可以根据需要再一步进行扩展。 核心层由控制者统一调度,将任务发给工人队列中的工人进行爬取操作。各个结点动态的向监控模块发送模块状态等信息,统一由展示层展示。 项目目标 众推,开源版的今日头条! 基于hadoop思维的分布式网络爬虫。 目前已经将fourinone、jeesite、webmagic整合进来,并且进一步进行改进。想最终做成一个基于设计器的动态可配置的分布式爬虫系统,这个是第一阶段的目标。 项目目前情况 目前项目进展情况: 1、sourceer,可以接入多种数据源,接口已经定义(加入builder封装,可以使用简单爬虫)。 2、web架构工程(web工程上传并测试成功,权限、基础框架改造,导入等已经录成视频,删除activiti,删除cms部分)。 3、分布式框架研究(分布式项目分包,添加部分注释,测试单机单工人爬取)。 4、插件化整合。 5、文章等各种去重方式及算法(目前已实现bloomfilter,指纹算法去重,已经实现simhash,分词算法(ansj))。 6、分类器测试(bayes,文本分类单机测试成功)。 项目地址: (分布式爬虫)http://git.oschina.net/zongtui/zongtui-webcrawler (去重过滤器)https://git.oschina.net/zongtui/zongtui-filter (文本分类器)https://git.oschina.net/zongtui/zongtui-classifier (文档目录)https://git.oschina.net/zongtui/zongtui-doc 项目界面: 启动jetty,目前皮肤暂时还未换。 总结 目前项目正在进一步完善当中,希望能得到你更多的意见!
openKM 想问下有没有这样的开源文件管理系统,所有人都可以上传文件,只有有权限的管理员才可以下载他人的文件? 不知道openkm能不能做到。 OpenKM是一个开放源代码的电子文档管理系统,它的特点是可用于大型公司或是中小企业, 适应性比较强。 并且在知识管理方面的加工,提供了更加灵活和成本较低的替代应用。 界面如下: zongtui项目 项目地址: (分布式爬虫)http://git.oschina.net/zongtui/zongtui-webcrawler (去重过滤器)https://git.oschina.net/zongtui/zongtui-filter (文本分类器)https://git.oschina.net/zongtui/zongtui-classifier (文档目录)https://git.oschina.net/zongtui/zongtui-doc 然后再推荐一篇文章:(深度学习 vs 机器学习 vs 模式识别) http://www.itd4j.com/cloudcomputing/15538.html 自动化部署 请问 有Java的自动化部署工具推荐不? 有时候修改几个文件就要重新打包发布重启,太麻烦了,请问有什么更好的办法么? Jenkins是一个开源软件项目,旨在提供一个开放易用的软件平台,使持续集成变成可能经济界。 云爬取 就是有一个客户端要爬取一千个商品,他可以提交给服务器,然后有服务器在分配给其它客户端来爬取。这样搞性能比较高,还能逃过IP限制。 那就是用户要爬什么资料。你就让用户自己去爬取。服务端只负责,接收任务,分配任务,返回任务。 等于是免费的ip池而已。。 项目新架构 经过讨论,目前的项目新架构已经修改如下: 这样,问题的集中点就在如何接入爬虫上了,因为现在各种爬虫已经太多,没必要在搞一个什么新鲜的东西! core部分的思路参考: 下一步的处理 1.通过设定规则抓取页面; 2.设定页面存储方案; 3.通过页面材料分析出内容属性; 4.通过内容属性生成结果; 5.通过结果进行学习; 6.通过结果生成内容; 说一下为什么接入其它的,我举两个例子 1、webmagic 就我知道,这哥们写了2年,基本上各种问题都遇到过。没必要再走一遍它的路,如果有问题可以通过它预留的接口帮它完善,或者直接用自己的实现。比如有性能问题,就我知道现在国内没有一个比较权威的对各种爬虫做比较。 2、Nutch 是一个开源Java 实现的搜索引擎。它提供了我们运行自己的搜索引擎所需的全部工具。包括全文搜索和Web爬虫。 Nutch的创始人是Doug Cutting,他同时也是Lucene、Hadoop和Avro开源项目的创始人。 说它有问题我觉得只有这么几种可能: 1、场景不适合。 2、没理解,没用明白。 所以我觉得没必要非得造个轮子。 个性化推荐 用户端就是数据呈现了,我的理解是内容方主要的工作是:采集、整理、推荐、打TAG、分值(多个)、推荐、赞、踩、回复数、类型(图文、视频、文本、微信、微博等); 用户这边的东西就确实高级很多:单体关系画像,不同社交圈关系画像,主要人群划分TAG得分,年龄、性别、职业、特别事件、喜欢内容TAG得分、收藏内容TAG得分、分享内容TAG得分、不感兴趣内容TAG得分(负值或其他分数) 推荐引擎主要的工作:按照用户的tag得分匹配内容,结合地理位置(当前的和常用的)、当前时间段(早、中、下、晚)、当前日期(节日、周末)、热点实时注册的时候选择标签这个是SNS的做法了,头条现在基本上都是从用户关系拿了关联用户数据再来推。 众推只要完成了初步的推荐功能,其他的基本上都是靠运营的人来积累数据。没有足够的数据肯定精准度要差点。比如一点资讯,现在内容差不多已经全搬过来了,但是推荐还是很烂,主要靠套用头条的编辑推荐那块,人工加了点分值。要不然感觉推荐会更加不准。
什么是Redis Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助。 Memcached和Redis Memcached的基本应用模型如下图所示: redis使用与其相同,将memcached改为redis即可。 Redis支持的数据类型 字符串(Strings) 字符串是Redis值的最基础的类型。Redis字符串是二进制安全的,这意味着一个Redis字符串可以包含任何种类的数据,例如一个JPEG图像或者一个序列化的Ruby对象。 一个字符串值最多可以保存512M字节的内容。 你可以使用Redis的字符串做一些有趣的事情,例如你可以: 在使用命令INCR系列( INCR, DECR, INCRBY)命令时将字符串作为的原子计数器。 使用APPEND命令追加字符串。 将字符串作为GETRANGE 和 SETRANGE的随机访问向量。 在小空间里编码大量数据, 或者使用 GETBIT 和 SETBIT创建一个Redis支持的Bloom过滤器。 列表(Lists) Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边) LPUSH 命令插入一个新的元素导头部, 而 RPUSH插入一个新元素导尾部.当一个这两个操作在一个空的Key上被执行的时候一个新的列表被创建。相似的,如果一个列表操作清空一个列表那么对应的key将被从key空间删除。这是非常方便的语义,因为他们被调用使用一个空列表完全就像他们被调用时使用一个不存在的键值(可以)做为参数。 一些类表操作和结果的例子: LPUSH mylist a # 现在类表中是 “a” LPUSH mylist b # 现在列表中是 “b”,”a” RPUSH mylist c # 现在类表中是 “b”,”a”,”c” (这次RPUSH被使用) 一个列表最多可以包含 232 – 1 个元素 (4294967295, 每个列表超过40亿个元素)。 从时间复杂度的角度来看Redis列表的主要特征是在头和尾的元素插入和删除是固定时间,即便是数以百万计的插入。. 在列表的两端访问元素是非常快的但是如果你试着访问一个非常大的列表的中间的元素是很慢的,因为那是一个O(N)操作。 你可以用Redis列表做很多有趣的事情,比如你可以: 在一个社交网络中建立一个时间线模型,使用LPUSH 去添加新的元素到用户的时间线, 使用LRANGE去接收一些最近插入的元素。 你可以将 LPUSH 和 LTRIM 一起用去创建一个永远也不会超过指定元素数目的列表,但是记住是最后的N个元素。 列表能够被用来作为消息传递primitive[译注:不清楚表达的意思], 例如众所周知的用来创建后台工作的Resque Ruby库. 你可以使用列表做更多的事,这个数据类型支持许多命令,包括像BLPOP这样的阻塞命令。 集合(Sets) Redis 集合(Set)是一个无序的字符串集合. 你可以以O(1)的时间复杂度 (无论集合中有多少元素时间复杂度都是常量)完成添加,删除,以及测试元素是否存在。 Redis 集合拥有令人满意的不允许包含相同成员的属性。多次添加相同的元素,最终在集合里只会有一个元素。 实际上说这些就是意味着在添加元素的时候无须检测元素是否存在。 一个Redis集合的非常有趣的事情是他支持一些服务端的命令从现有的集合出发去进行集合运算,因此你可以在非常短的时间内进行合并(unions), 求交集(intersections),找出不同的元素(differences of sets)。 一个集合最多可以包含 232 – 1 个元素(4294967295, 每个集合超过40一个元素). 你可以使用集合多很多有趣的事情,比如你能够: 你可以使用集合追踪一件(独一无二的)事情,想要知道所有访问一个博客文章的独立IP? 每次当你处理一个页面访问的事简单的使用SADD。你可以肯定重复的IP是不会被插入的。 Redis 集合是很擅长表现关系的。你可以使用Redis集合创建一个tagging系统去表现每一个tag。接下来你能够使用SADD命令将有一个给定tag的所有对象的所有ID添加到一个用来展现这个特定tag的集合里。你想要同时有三个不同tag的所有对象的ID吗?使用SINTER就好了。 使用 SPOP 或者 SRANDMEMBER 命令你可以使用集合去随意的抽取元素。 哈希(Hashes) Redis Hashes是字符串字段和字符串值之间的映射,因此他们是展现对象的完美数据类型。 (例如:一个有名,姓,年龄等等属性的用户): @cli HMSET user:1000 username antirez password P1pp0 age 34 HGETALL user:1000 HSET user:1000 password 12345 HGETALL user:1000 一个带有一些字段(这里的一些意味着高达一百左右)的hash仅仅需要一块很小的空间存储,因此你可以存储数以百万计的对象在一个小的Redis实例中。 哈希主要用来表现对象,他们有能力存储很多对象,因此你可以将哈希用于许多其他的任务。 每一个哈希可以存储超过232 – 1 字段-值 对 (超过40亿). 有序集合(Sorted Sets) Redis有序集合与普通集合非常相似,是一个没有重复元素的字符串集合。不同之处是有序集合的没有成员都关联了一个评分,这个评分被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复了。 使用有序集合你可以以非常快的速度(O(log(N)))添加,删除和更新元素。因为元素是有序的, 所以你也可以很快的根据评分(score)或者次序(position)来获取一个范围的元素。访问有序集合的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员的智能列表。在有序集合中,你可以很快捷的访问一切你需要的东西:有序的元素,快速的存在性测试,快速访问集合的中间元素! 简而言之使用有序集合你可以做完成许多对性能有极端要求的任务,而那些任务使用其他类型的数据库真的是很难完成的。 使用有序集合你可以: 在一个大型的在线游戏中展示一个排行榜,在那里一旦一个新的分数被提交,你可以使用ZADD命令去更新它.你也可用使用 ZRANGE命令来得到顶级的用户,你还可以使用ZRANK命令根据用户名返回该用户在排行榜中的位次。同时使用ZRANK 和 ZRANGE 你可以显示和给定用户分数相同的所有用户。所有这些操作都非常的快速。 有序集合常常被用来索引存储在Redis中的数据。举个例子,如果你有许多的哈希(Hashes)来代表用户,你可以使用一个有序集合,这个集合中的元素的年龄字段被用来当做评分,而ID作为值。因此,使用 ZRANGEBYSCORE 命令,那是微不足道的并且能够很快的接收到给定年龄段的所有用户。 centos安装redis wget http://download.redis.io/redis-stable.tar.gz tar xvzf redis-stable.tar.gz cd redis-stable make 前面3步应该没有问题,主要的问题是执行make的时候,出现了异常。 异常一: make[2]: cc: Command not found 异常原因:没有安装gcc 解决方案:yum install gcc-c++ 异常二: zmalloc.h:51:31: error: jemalloc/jemalloc.h: No such file or directory 异常原因:一些编译依赖或原来编译遗留出现的问题 解决方案:make distclean。清理一下,然后再make。 在make成功以后,需要make test。在make test出现异常。 异常一: couldn’t execute “tclsh8.5″: no such file or directory 异常原因:没有安装tcl 解决方案:yum install -y tcl。 在make成功以后,会在src目录下多出一些可执行文件:redis-server,redis-cli等等。 方便期间用cp命令复制到usr目录下运行。 cp redis-server /usr/local/bin/ cp redis-cli /usr/local/bin/ 然后新建目录,存放配置文件 mkdir /etc/redis mkdir /var/redis mkdir /var/redis/log mkdir /var/redis/run mkdir /var/redis/6379 在redis解压根目录中找到配置文件模板,复制到如下位置。 cp redis.conf /etc/redis/6379.conf 通过vim命令修改 daemonize yes pidfile /var/redis/run/redis_6379.pid logfile /var/redis/log/redis_6379.log dir /var/redis/6379 最后运行redis: $ redis-server /etc/redis/6379.conf 使用Jedis操作Redis 使用Java操作Redis需要jedis-2.1.0.jar,下载地址:http://files.cnblogs.com/liuling/jedis-2.1.0.jar.zip 如果需要使用Redis连接池的话,还需commons-pool-1.5.4.jar,下载地址:http://files.cnblogs.com/liuling/commons-pool-1.5.4.jar.zip 也可以使用maven引入: <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.0.0</version> <type>jar</type> <scope>compile</scope> </dependency> package com.test; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.junit.Before; import org.junit.Test; import redis.clients.jedis.Jedis; public class TestRedis { private Jedis jedis; @Before public void setup() { //连接redis服务器,192.168.0.100:6379 jedis = new Jedis("192.168.0.100", 6379); //权限认证 jedis.auth("admin"); } /** * redis存储字符串 */ @Test public void testString() { //-----添加数据---------- jedis.set("name","xinxin");//向key-->name中放入了value-->xinxin System.out.println(jedis.get("name"));//执行结果:xinxin jedis.append("name", " is my lover"); //拼接 System.out.println(jedis.get("name")); jedis.del("name"); //删除某个键 System.out.println(jedis.get("name")); //设置多个键值对 jedis.mset("name","liuling","age","23","qq","476777389"); jedis.incr("age"); //进行加1操作 System.out.println(jedis.get("name") + "-" + jedis.get("age") + "-" + jedis.get("qq")); } /** * redis操作Map */ @Test public void testMap() { //-----添加数据---------- Map<String, String> map = new HashMap<String, String>(); map.put("name", "xinxin"); map.put("age", "22"); map.put("qq", "123456"); jedis.hmset("user",map); //取出user中的name,执行结果:[minxr]-->注意结果是一个泛型的List //第一个参数是存入redis中map对象的key,后面跟的是放入map中的对象的key,后面的key可以跟多个,是可变参数 List<String> rsmap = jedis.hmget("user", "name", "age", "qq"); System.out.println(rsmap); //删除map中的某个键值 jedis.hdel("user","age"); System.out.println(jedis.hmget("user", "age")); //因为删除了,所以返回的是null System.out.println(jedis.hlen("user")); //返回key为user的键中存放的值的个数2 System.out.println(jedis.exists("user"));//是否存在key为user的记录 返回true System.out.println(jedis.hkeys("user"));//返回map对象中的所有key System.out.println(jedis.hvals("user"));//返回map对象中的所有value Iterator<String> iter=jedis.hkeys("user").iterator(); while (iter.hasNext()){ String key = iter.next(); System.out.println(key+":"+jedis.hmget("user",key)); } } /** * jedis操作List */ @Test public void testList(){ //开始前,先移除所有的内容 jedis.del("java framework"); System.out.println(jedis.lrange("java framework",0,-1)); //先向key java framework中存放三条数据 jedis.lpush("java framework","spring"); jedis.lpush("java framework","struts"); jedis.lpush("java framework","hibernate"); //再取出所有数据jedis.lrange是按范围取出, // 第一个是key,第二个是起始位置,第三个是结束位置,jedis.llen获取长度 -1表示取得所有 System.out.println(jedis.lrange("java framework",0,-1)); jedis.del("java framework"); jedis.rpush("java framework","spring"); jedis.rpush("java framework","struts"); jedis.rpush("java framework","hibernate"); System.out.println(jedis.lrange("java framework",0,-1)); } /** * jedis操作Set */ @Test public void testSet(){ //添加 jedis.sadd("user","liuling"); jedis.sadd("user","xinxin"); jedis.sadd("user","ling"); jedis.sadd("user","zhangxinxin"); jedis.sadd("user","who"); //移除noname jedis.srem("user","who"); System.out.println(jedis.smembers("user"));//获取所有加入的value System.out.println(jedis.sismember("user", "who"));//判断 who 是否是user集合的元素 System.out.println(jedis.srandmember("user")); System.out.println(jedis.scard("user"));//返回集合的元素个数 } @Test public void test() throws InterruptedException { //jedis 排序 //注意,此处的rpush和lpush是List的操作。是一个双向链表(但从表现来看的) jedis.del("a");//先清除数据,再加入数据进行测试 jedis.rpush("a", "1"); jedis.lpush("a","6"); jedis.lpush("a","3"); jedis.lpush("a","9"); System.out.println(jedis.lrange("a",0,-1));// [9, 3, 6, 1] System.out.println(jedis.sort("a")); //[1, 3, 6, 9] //输入排序后结果 System.out.println(jedis.lrange("a",0,-1)); } @Test public void testRedisPool() { RedisUtil.getJedis().set("newname", "中文测试"); System.out.println(RedisUtil.getJedis().get("newname")); } } Redis连接池: package com.test; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; public final class RedisUtil { //Redis服务器IP private static String ADDR = "192.168.0.100"; //Redis的端口号 private static int PORT = 6379; //访问密码 private static String AUTH = "admin"; //可用连接实例的最大数目,默认值为8; //如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。 private static int MAX_ACTIVE = 1024; //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。 private static int MAX_IDLE = 200; //等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException; private static int MAX_WAIT = 10000; private static int TIMEOUT = 10000; //在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的; private static boolean TEST_ON_BORROW = true; private static JedisPool jedisPool = null; /** * 初始化Redis连接池 */ static { try { JedisPoolConfig config = new JedisPoolConfig(); config.setMaxActive(MAX_ACTIVE); config.setMaxIdle(MAX_IDLE); config.setMaxWait(MAX_WAIT); config.setTestOnBorrow(TEST_ON_BORROW); jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH); } catch (Exception e) { e.printStackTrace(); } } /** * 获取Jedis实例 * @return */ public synchronized static Jedis getJedis() { try { if (jedisPool != null) { Jedis resource = jedisPool.getResource(); return resource; } else { return null; } } catch (Exception e) { e.printStackTrace(); return null; } } /** * 释放jedis资源 * @param jedis */ public static void returnResource(final Jedis jedis) { if (jedis != null) { jedisPool.returnResource(jedis); } } } 总结 在使用缓存的时候,redis比memcached具有更多的优势,并且支持更多的数据类型。
Spark简介 Spark是UC Berkeley AMP lab所开源的类Hadoop MapReduce的通用的并行,Spark,拥有Hadoop MapReduce所具有的优点;但不同于MapReduce的是Job中间输出结果可以保存在内存中,从而不再需要读写HDFS,因此Spark能更好地适用于数据挖掘与机器学习等需要迭代的map reduce的算法。 Spark优点 Spark是基于内存,是云计算领域的继Hadoop之后的下一代的最热门的通用的并行计算框架开源项目,尤其出色的支持Interactive Query、流计算、图计算等。 Spark在机器学习方面有着无与伦比的优势,特别适合需要多次迭代计算的算法。同时Spark的拥有非常出色的容错和调度机制,确保系统的稳定运行,Spark目前的发展理念是通过一个计算框架集合SQL、Machine Learning、Graph Computing、Streaming Computing等多种功能于一个项目中,具有非常好的易用性。目前SPARK已经构建了自己的整个大数据处理生态系统,如流处理、图技术、机器学习、NoSQL查询等方面都有自己的技术,并且是Apache顶级Project,可以预计的是2014年下半年在社区和商业应用上会有爆发式的增长。Spark最大的优势在于速度,在迭代处理计算方面比Hadoop快100倍以上;Spark另外一个无可取代的优势是:“One Stack to rule them all”,Spark采用一个统一的技术堆栈解决了云计算大数据的所有核心问题,这直接奠定了其一统云计算大数据领域的霸主地位; 下图是使用逻辑回归算法的使用时间: Spark目前支持scala、python、JAVA编程。 作为Spark的原生语言,scala是开发Spark应用程序的首选,其优雅简洁的代码,令开发过mapreduce代码的码农感觉象是上了天堂。 可以架构在hadoop之上,读取hadoop、hbase数据。 spark的部署方式 1、standalone模式,即独立模式,自带完整的服务,可单独部署到一个集群中,无需依赖任何其他资源管理系统。 2、Spark On Mesos模式。这是很多公司采用的模式,官方推荐这种模式(当然,原因之一是血缘关系)。 3、Spark On YARN模式。这是一种最有前景的部署模式。 spark本机安装 流程:进入linux->安装JDK->安装scala->安装spark。 JDK的安装和配置(略)。 安装scala,进入http://www.scala-lang.org/download/下载。 下载后解压缩。 tar zxvf scala-2.11.6.tgz //改名 mv scala-2.11.6 scala //设置配置 export SCALA_HOME=/home/hadoop/software/scala export PATH=$SCALA_HOME/bin;$PATH source /etc/profile scala -version Scala code runner version 2.11.6 -- Copyright 2002-2013, LAMP/EPFL scala设置成功。 从http://spark.apache.org/downloads.html下载spark并安装。 下载后解压缩。 进入$SPARK_HOME/bin,运行 ./run-example SparkPi 运行结果 Spark assembly has been built with Hive, including Datanucleus jars on classpath Using Spark's default log4j profile: org/apache/spark/log4j-defaults.properties 15/03/14 23:41:40 INFO SparkContext: Running Spark version 1.3.0 15/03/14 23:41:40 WARN Utils: Your hostname, localhost.localdomain resolves to a loopback address: 127.0.0.1; using 192.168.126.147 instead (on interface eth0) 15/03/14 23:41:40 WARN Utils: Set SPARK_LOCAL_IP if you need to bind to another address 15/03/14 23:41:41 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable 15/03/14 23:41:41 INFO SecurityManager: Changing view acls to: hadoop 15/03/14 23:41:41 INFO SecurityManager: Changing modify acls to: hadoop 15/03/14 23:41:41 INFO SecurityManager: SecurityManager: authentication disabled; ui acls disabled; users with view permissions: Set(hadoop); users with modify permissions: Set(hadoop) 15/03/14 23:41:42 INFO Slf4jLogger: Slf4jLogger started 15/03/14 23:41:42 INFO Remoting: Starting remoting 15/03/14 23:41:42 INFO Remoting: Remoting started; listening on addresses :[akka.tcp://sparkDriver@192.168.126.147:60926] 15/03/14 23:41:42 INFO Utils: Successfully started service 'sparkDriver' on port 60926. 15/03/14 23:41:42 INFO SparkEnv: Registering MapOutputTracker 15/03/14 23:41:43 INFO SparkEnv: Registering BlockManagerMaster 15/03/14 23:41:43 INFO DiskBlockManager: Created local directory at /tmp/spark-285a6144-217c-442c-bfde-4b282378ac1e/blockmgr-f6cb0d15-d68d-4079-a0fe-9ec0bf8297a4 15/03/14 23:41:43 INFO MemoryStore: MemoryStore started with capacity 265.1 MB 15/03/14 23:41:43 INFO HttpFileServer: HTTP File server directory is /tmp/spark-96b3f754-9cad-4ef8-9da7-2a2c5029c42a/httpd-b28f3f6d-73f7-46d7-9078-7ba7ea84ca5b 15/03/14 23:41:43 INFO HttpServer: Starting HTTP Server 15/03/14 23:41:43 INFO Server: jetty-8.y.z-SNAPSHOT 15/03/14 23:41:43 INFO AbstractConnector: Started SocketConnector@0.0.0.0:42548 15/03/14 23:41:43 INFO Utils: Successfully started service 'HTTP file server' on port 42548. 15/03/14 23:41:43 INFO SparkEnv: Registering OutputCommitCoordinator 15/03/14 23:41:43 INFO Server: jetty-8.y.z-SNAPSHOT 15/03/14 23:41:43 INFO AbstractConnector: Started SelectChannelConnector@0.0.0.0:4040 15/03/14 23:41:43 INFO Utils: Successfully started service 'SparkUI' on port 4040. 15/03/14 23:41:43 INFO SparkUI: Started SparkUI at http://192.168.126.147:4040 15/03/14 23:41:44 INFO SparkContext: Added JAR file:/home/hadoop/software/spark-1.3.0-bin-hadoop2.4/lib/spark-examples-1.3.0-hadoop2.4.0.jar at http://192.168.126.147:42548/jars/spark-examples-1.3.0-hadoop2.4.0.jar with timestamp 1426347704488 15/03/14 23:41:44 INFO Executor: Starting executor ID <driver> on host localhost 15/03/14 23:41:44 INFO AkkaUtils: Connecting to HeartbeatReceiver: akka.tcp://sparkDriver@192.168.126.147:60926/user/HeartbeatReceiver 15/03/14 23:41:44 INFO NettyBlockTransferService: Server created on 39408 15/03/14 23:41:44 INFO BlockManagerMaster: Trying to register BlockManager 15/03/14 23:41:44 INFO BlockManagerMasterActor: Registering block manager localhost:39408 with 265.1 MB RAM, BlockManagerId(<driver>, localhost, 39408) 15/03/14 23:41:44 INFO BlockManagerMaster: Registered BlockManager 15/03/14 23:41:45 INFO SparkContext: Starting job: reduce at SparkPi.scala:35 15/03/14 23:41:45 INFO DAGScheduler: Got job 0 (reduce at SparkPi.scala:35) with 2 output partitions (allowLocal=false) 15/03/14 23:41:45 INFO DAGScheduler: Final stage: Stage 0(reduce at SparkPi.scala:35) 15/03/14 23:41:45 INFO DAGScheduler: Parents of final stage: List() 15/03/14 23:41:45 INFO DAGScheduler: Missing parents: List() 15/03/14 23:41:45 INFO DAGScheduler: Submitting Stage 0 (MapPartitionsRDD[1] at map at SparkPi.scala:31), which has no missing parents 15/03/14 23:41:45 INFO MemoryStore: ensureFreeSpace(1848) called with curMem=0, maxMem=278019440 15/03/14 23:41:45 INFO MemoryStore: Block broadcast_0 stored as values in memory (estimated size 1848.0 B, free 265.1 MB) 15/03/14 23:41:45 INFO MemoryStore: ensureFreeSpace(1296) called with curMem=1848, maxMem=278019440 15/03/14 23:41:45 INFO MemoryStore: Block broadcast_0_piece0 stored as bytes in memory (estimated size 1296.0 B, free 265.1 MB) 15/03/14 23:41:45 INFO BlockManagerInfo: Added broadcast_0_piece0 in memory on localhost:39408 (size: 1296.0 B, free: 265.1 MB) 15/03/14 23:41:45 INFO BlockManagerMaster: Updated info of block broadcast_0_piece0 15/03/14 23:41:45 INFO SparkContext: Created broadcast 0 from broadcast at DAGScheduler.scala:839 15/03/14 23:41:45 INFO DAGScheduler: Submitting 2 missing tasks from Stage 0 (MapPartitionsRDD[1] at map at SparkPi.scala:31) 15/03/14 23:41:45 INFO TaskSchedulerImpl: Adding task set 0.0 with 2 tasks 15/03/14 23:41:45 INFO TaskSetManager: Starting task 0.0 in stage 0.0 (TID 0, localhost, PROCESS_LOCAL, 1340 bytes) 15/03/14 23:41:45 INFO TaskSetManager: Starting task 1.0 in stage 0.0 (TID 1, localhost, PROCESS_LOCAL, 1340 bytes) 15/03/14 23:41:45 INFO Executor: Running task 1.0 in stage 0.0 (TID 1) 15/03/14 23:41:45 INFO Executor: Running task 0.0 in stage 0.0 (TID 0) 15/03/14 23:41:45 INFO Executor: Fetching http://192.168.126.147:42548/jars/spark-examples-1.3.0-hadoop2.4.0.jar with timestamp 1426347704488 15/03/14 23:41:45 INFO Utils: Fetching http://192.168.126.147:42548/jars/spark-examples-1.3.0-hadoop2.4.0.jar to /tmp/spark-db1e742b-020f-4db1-9ee3-f3e2d90e1bc2/userFiles-96c6db61-e95e-4f9e-a6c4-0db892583854/fetchFileTemp5600234414438914634.tmp 15/03/14 23:41:46 INFO Executor: Adding file:/tmp/spark-db1e742b-020f-4db1-9ee3-f3e2d90e1bc2/userFiles-96c6db61-e95e-4f9e-a6c4-0db892583854/spark-examples-1.3.0-hadoop2.4.0.jar to class loader 15/03/14 23:41:47 INFO Executor: Finished task 1.0 in stage 0.0 (TID 1). 736 bytes result sent to driver 15/03/14 23:41:47 INFO Executor: Finished task 0.0 in stage 0.0 (TID 0). 736 bytes result sent to driver 15/03/14 23:41:47 INFO TaskSetManager: Finished task 0.0 in stage 0.0 (TID 0) in 1560 ms on localhost (1/2) 15/03/14 23:41:47 INFO TaskSetManager: Finished task 1.0 in stage 0.0 (TID 1) in 1540 ms on localhost (2/2) 15/03/14 23:41:47 INFO TaskSchedulerImpl: Removed TaskSet 0.0, whose tasks have all completed, from pool 15/03/14 23:41:47 INFO DAGScheduler: Stage 0 (reduce at SparkPi.scala:35) finished in 1.578 s 15/03/14 23:41:47 INFO DAGScheduler: Job 0 finished: reduce at SparkPi.scala:35, took 2.099817 s Pi is roughly 3.14438 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/metrics/json,null} 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/stages/stage/kill,null} 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/,null} 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/static,null} 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/executors/threadDump/json,null} 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/executors/threadDump,null} 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/executors/json,null} 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/executors,null} 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/environment/json,null} 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/environment,null} 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/storage/rdd/json,null} 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/storage/rdd,null} 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/storage/json,null} 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/storage,null} 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/stages/pool/json,null} 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/stages/pool,null} 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/stages/stage/json,null} 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/stages/stage,null} 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/stages/json,null} 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/stages,null} 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/jobs/job/json,null} 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/jobs/job,null} 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/jobs/json,null} 15/03/14 23:41:47 INFO ContextHandler: stopped o.s.j.s.ServletContextHandler{/jobs,null} 15/03/14 23:41:47 INFO SparkUI: Stopped Spark web UI at http://192.168.126.147:4040 15/03/14 23:41:47 INFO DAGScheduler: Stopping DAGScheduler 15/03/14 23:41:47 INFO MapOutputTrackerMasterActor: MapOutputTrackerActor stopped! 15/03/14 23:41:47 INFO MemoryStore: MemoryStore cleared 15/03/14 23:41:47 INFO BlockManager: BlockManager stopped 15/03/14 23:41:47 INFO BlockManagerMaster: BlockManagerMaster stopped 15/03/14 23:41:47 INFO OutputCommitCoordinator$OutputCommitCoordinatorActor: OutputCommitCoordinator stopped! 15/03/14 23:41:47 INFO SparkContext: Successfully stopped SparkContext 15/03/14 23:41:47 INFO RemoteActorRefProvider$RemotingTerminator: Shutting down remote daemon. 15/03/14 23:41:47 INFO RemoteActorRefProvider$RemotingTerminator: Remote daemon shut down; proceeding with flushing remote transports. 可以看到输出结果为3.14438。
在2020年,专业技术知识将不再是IT部门的唯一领域了。整个公司/组织的员工应当要理解如何把IT技术运用到他们的工作之中。但未来学家和IT专家说,最吃香的IT相关技术包括:挖掘海量数据、保护系统免遭安全威胁、管理新系统下日益复杂的风险以及如何利用技术提高生产率。虽然IT知识将更加普及,但雇主们将更加青睐如下5种专用技能。 1.数据分析 据IDC市场研究人员估计,到2020年全球每年产生的数据量将达到35ZB,也就是3500万亿GB。(注:1ZB=1,048,576PB;1PB=1,048,576GB;这个数据很抽象。)IDC的首席研究员JohnGantz说:“用普通的DVD一张一张地摞起来,可以从地球摞两个堆到月球。” 有了这样庞大的数据,这就不仅要求IT从业人员有能力分析海量数据,并且要和业务部门合作,确认哪些数据是可用的,从哪里获取这些有用的数据。 这些混合型的从业人员将同时具备IT专长和业务流程与运作的知识背景。IT人力研究机构FootePartners公司的董事长兼CEODavidFoote说:“他们是那些了解客户需求的,并且知道如何把信息转换为赢利的人。如果你有更多这样的理解整个数据‘供应链’的雇员,你的获利也更多。” 2.风险管理 未来学家DavidPearceSnyder说:“风险管理技能的高需求将会持续到2020年,尤其当(各种)业务和愈发愈发的IT之间关系很紧密。比如,前段时间英国石油在墨西哥湾的油井泄漏中所涉及的IT技术,还有丰田公司处理‘加速门’事件。”(编者注:丰田承认汽车黑匣子阅读器存在软件缺陷。) Snyder还说:“当我们处于快速创新的时代(这一趋势将持续到2020年),我们会碰到意想不到法律问题;当我们想在这错综复杂的世界搞点创新,很肯能就要碰到这样或那样的问题。”(所以,)企业将寻求具备有风险管理能力的IT从业人员,以预测和应对挑战。 3.机器人技术 据华盛顿的未来咨询学家JosephCoates说,机器人将在2020年之前“接管”更多的工作。所以,具备机器人技术的IT从业人员将不愁没有饭吃。 Coates说:“我们可以把机器人看成类人设备,但我们还需扩大到所有自动化的设备。”机器人技术工作包括:研发、维护和修理。专家将在垂直市场探索相关技术的使用。比如:一些机器人专家可能专注健康护理和研发康复中心的设施,另一些专家肯能为残疾人发明设备或为儿童发明学习工具。 4.信息安全 根据PricewaterhouseCoopers的报告:因为我们上网所花的时间将越来越多,面对面的交互将越来越少,更多的个人信息将在网上曝光,可以轻易冒充他人的新技术也很多,所以在2020年之前,认证用户身份和保护隐私将成重大挑战。远程工作人员也将成为劳动大军的主力,这也就带来更多的信息安全隐患。 编者注:“远程工作人员”也称“居家工作人员”,即那些可以在家通过网络即可上班的人员。 Foote解释说:“我们处于一个危险的环境,虽然很多雇员都精通技术,但他们却并不理解信息安全是最重要的。”Foote预测这个状况将在2020年有改善,因为很多公司将信息安全方面投入更多,包括数据中心、网络连接和远程访问。 5.网络技术 Snyder回应美国劳工统计局的预测说,“网络系统和数据通信管理在2020年仍将是头等大事,但是因为很多公司将想方设法避免增员,所以他们向顾问咨询如何提高产能和效率。” “如果已经尽量裁员了,那么现在只能提高生产率了。应当有人来告诉我们如何更好地使用现有的网络技术。”
许多分布式计算系统都可以实时或接近实时地处理大数据流。本文将对三种Apache框架分别进行简单介绍,然后尝试快速、高度概述其异同。 Apache Storm 在Storm中,先要设计一个用于实时计算的图状结构,我们称之为拓扑(topology)。这个拓扑将会被提交给集群,由集群中的主控节点(master node)分发代码,将任务分配给工作节点(worker node)执行。一个拓扑中包括spout和bolt两种角色,其中spout发送消息,负责将数据流以tuple元组的形式发送出去;而bolt则负责转换这些数据流,在bolt中可以完成计算、过滤等操作,bolt自身也可以随机将数据发送给其他bolt。由spout发射出的tuple是不可变数组,对应着固定的键值对。 Apache Spark Spark Streaming是核心Spark API的一个扩展,它并不会像Storm那样一次一个地处理数据流,而是在处理前按时间间隔预先将其切分为一段一段的批处理作业。Spark针对持续性数据流的抽象称为DStream(DiscretizedStream),一个DStream是一个微批处理(micro-batching)的RDD(弹性分布式数据集);而RDD则是一种分布式数据集,能够以两种方式并行运作,分别是任意函数和滑动窗口数据的转换。 Apache Samza Samza处理数据流时,会分别按次处理每条收到的消息。Samza的流单位既不是元组,也不是Dstream,而是一条条消息。在Samza中,数据流被切分开来,每个部分都由一组只读消息的有序数列构成,而这些消息每条都有一个特定的ID(offset)。该系统还支持批处理,即逐次处理同一个数据流分区的多条消息。Samza的执行与数据流模块都是可插拔式的,尽管Samza的特色是依赖Hadoop的Yarn(另一种资源调度器)和Apache Kafka。 共同之处 以上三种实时计算系统都是开源的分布式系统,具有低延迟、可扩展和容错性诸多优点,它们的共同特色在于:允许你在运行数据流代码时,将任务分配到一系列具有容错能力的计算机上并行运行。此外,它们都提供了简单的API来简化底层实现的复杂程度。 三种框架的术语名词不同,但是其代表的概念十分相似: 对比图 下面表格总结了一些不同之处: 数据传递形式分为三大类: 最多一次(At-most-once):消息可能会丢失,这通常是最不理想的结果。 最少一次(At-least-once):消息可能会再次发送(没有丢失的情况,但是会产生冗余)。在许多用例中已经足够。 恰好一次(Exactly-once):每条消息都被发送过一次且仅仅一次(没有丢失,没有冗余)。这是最佳情况,尽管很难保证在所有用例中都实现。 另一个方面是状态管理:对状态的存储有不同的策略,Spark Streaming将数据写入分布式文件系统中(例如HDFS);Samza使用嵌入式键值存储;而在Storm中,或者将状态管理滚动至应用层面,或者使用更高层面的抽象Trident。 用例 这三种框架在处理连续性的大量实时数据时的表现均出色而高效,那么使用哪一种呢?选择时并没有什么硬性规定,最多就是几个指导方针。 如果你想要的是一个允许增量计算的高速事件处理系统,Storm会是最佳选择。它可以应对你在客户端等待结果的同时,进一步进行分布式计算的需求,使用开箱即用的分布式RPC(DRPC)就可以了。最后但同样重要的原因:Storm使用Apache Thrift,你可以用任何编程语言来编写拓扑结构。如果你需要状态持续,同时/或者达到恰好一次的传递效果,应当看看更高层面的Trdent API,它同时也提供了微批处理的方式。 使用Storm的公司有:Twitter,雅虎,Spotify还有The Weather Channel等。 说到微批处理,如果你必须有状态的计算,恰好一次的递送,并且不介意高延迟的话,那么可以考虑Spark Streaming,特别如果你还计划图形操作、机器学习或者访问SQL的话,Apache Spark的stack允许你将一些library与数据流相结合(Spark SQL,Mllib,GraphX),它们会提供便捷的一体化编程模型。尤其是数据流算法(例如:K均值流媒体)允许Spark实时决策的促进。 使用Spark的公司有:亚马逊,雅虎,NASA JPL,eBay还有百度等。 如果你有大量的状态需要处理,比如每个分区都有许多十亿位元组,那么可以选择Samza。由于Samza将存储与处理放在同一台机器上,在保持处理高效的同时,还不会额外载入内存。这种框架提供了灵活的可插拔API:它的默认execution、消息发送还有存储引擎操作都可以根据你的选择随时进行替换。此外,如果你有大量的数据流处理阶段,且分别来自不同代码库的不同团队,那么Samza的细颗粒工作特性会尤其适用,因为它们可以在影响最小化的前提下完成增加或移除的工作。 使用Samza的公司有:LinkedIn,Intuit,Metamarkets,Quantiply,Fortscale等。 结论 本文中我们只对这三种Apache框架进行了简单的了解,并未覆盖到这些框架中大量的功能与更多细微的差异。同时,文中这三种框架对比也是受到限制的,因为这些框架都在一直不断的发展,这一点是我们应当牢记的。
项目背景 因为最近一直都在搞数据挖掘类的项目,且现在国内的大数据潮火热。在前几天与群里的几位兄弟聊天所以有了做一个开源项目的想法,以前也搞过一个开源的项目,当时只是想把权限集中化做一下,项目的名称和地址是: http://www.cnblogs.com/skyme/archive/2012/02/07/2341364.html 但是后期实在工作太忙,就搁置在那里了。 所以现在又搞了一个,目前方向已经大致明确,下边介绍一下思路。 仿今日头条 java+新闻等+仿今日头条+大数据分析和挖掘(分类器+聚类分析+推荐系统等) 经过大家几天的讨论,项目方向已经基本确定! 在github上会发起新项目 这个是讨论的投票结果,结果见下图。 系统定位 所有的app都可以接入,不重点做app端,而是做个性化推荐这一块,在服务端。 项目目前的思路如下图所示: 目的是提供一个大众化的信息收集系统,让今日头条中所使用的技术不再神秘。 有想参与的可以一起进来讨论 群号 194338168 想深度参与的加,不想参与的就别往里进了,现在需要的主要是开发和文档两类人。群会定期往出清人! (项目会开源出来)
Mahout中实现的推荐算法是协同过滤,而无论是UserCF还是ItemCF都依赖于user相似度或item相似度。本文是对mahout中的一些相似度算法的解读。 Mahout相似度相关类关系如下: 有点乱(^.^) 从上图可看出,Mahout主要针对用户相似度和物品相似度的计算,并且除了HybridSimilarity之外全都能够用于计算user和item两者的相似度,只有HybridSimilarity只能计算item相似度。接来下分三部分进行分析:继承AbstractSimilarity的,没有集成AbstractSimilarity但是也可以用于user、item相似度计算的,只继承AbstractItemSimilarity的。 继承AbstractSimilarity的实现类 以下这些类用于无偏好值的用户行为数据。 在介绍EuclideanDistanceSimilarity、PearsonCorrelationSimilarity、UncenteredCosineSimilarity之前,让我们先了解一下AbstractSimilarity。其实AbstractSimilarity才是这一部分的核心,三个重要方法:userSimilarity()、itemSimilarity()、computeResult(),其中computeResult()是抽象方法,是供给子类去实现的,userSimilarity()、itemSimilarity()中会在计算好相应变量之后调用子类实现的computeResult(),得到的结果在经过处理之后就是相似度。 在userSimilarity()中,会先计算 user1对物品X偏好值的和sumX以及平方和sumX2、user2对物品Y的偏好值的和sumY以及平方和sumY2、user1与user2的物品的偏好值的乘积sumXY、user1(item1)与user2(item2)的偏好值的平方差sumXYdiff2。代码如下: sumXY += x * y; sumX += x; sumX2 += x * x; sumY += y; sumY2 += y * y; double diff = x - y; sumXYdiff2 += diff * diff; count++; 其中如果一个user没有对某个item的偏好而另一个user有对这个item的偏好,那么会使用PreferenceInferrer实现类对进行推测,代码如下: // Only one user expressed a preference, but infer the other one's preference and tally // as if the other user expressed that preference if (compare < 0) { // X has a value; infer Y's x = hasPrefTransform ? prefTransform.getTransformedValue(xPrefs.get(xPrefIndex)) : xPrefs.getValue(xPrefIndex); y = inferrer.inferPreference(userID2, xIndex); } else { // compare > 0 // Y has a value; infer X's x = inferrer.inferPreference(userID1, yIndex); y = hasPrefTransform ? prefTransform.getTransformedValue(yPrefs.get(yPrefIndex)) : yPrefs.getValue(yPrefIndex); } 然后会调用computeResult()方法,代码如下: // "Center" the data. If my math is correct, this'll do it. double result; if (centerData) { double meanX = sumX / count; double meanY = sumY / count; // double centeredSumXY = sumXY - meanY * sumX - meanX * sumY + n * meanX * meanY; double centeredSumXY = sumXY - meanY * sumX; // double centeredSumX2 = sumX2 - 2.0 * meanX * sumX + n * meanX * meanX; double centeredSumX2 = sumX2 - meanX * sumX; // double centeredSumY2 = sumY2 - 2.0 * meanY * sumY + n * meanY * meanY; double centeredSumY2 = sumY2 - meanY * sumY; result = computeResult(count, centeredSumXY, centeredSumX2, centeredSumY2, sumXYdiff2); } else { result = computeResult(count, sumXY, sumX2, sumY2, sumXYdiff2); } 最后,在经过SimilarityTransform和normalizeWeightResult()两步处理,result就是求得的user1与user2的相似度数值。代码如下: if (similarityTransform != null) { result = similarityTransform.transformSimilarity(itemID1, itemID2, result); } if (!Double.isNaN(result)) { result = normalizeWeightResult(result, count, cachedNumUsers); } 1.PearsonCorrelationSimilarity 基于皮尔森相关性的相似度计算:sumXY / sqrt(sumX2 * sumY2),代码如下: @Override double computeResult(int n, double sumXY, double sumX2, double sumY2, double sumXYdiff2) { if (n == 0) { return Double.NaN; } // Note that sum of X and sum of Y don't appear here since they are assumed to be 0; // the data is assumed to be centered. double denominator = Math.sqrt(sumX2) * Math.sqrt(sumY2); if (denominator == 0.0) { // One or both parties has -all- the same ratings; // can't really say much similarity under this measure return Double.NaN; } return sumXY / denominator; } 2.EuclideanDistanceSimilarity 基于欧几里德距离的相似度计算:1 / (1 + distance),代码如下: @Override double computeResult(int n, double sumXY, double sumX2, double sumY2, double sumXYdiff2) { return 1.0 / (1.0 + Math.sqrt(sumXYdiff2) / Math.sqrt(n)); } 3.UncenteredCosineSimilarity 基于余弦的相似度计算,代码如下: @Override double computeResult(int n, double sumXY, double sumX2, double sumY2, double sumXYdiff2) { if (n == 0) { return Double.NaN; } double denominator = Math.sqrt(sumX2) * Math.sqrt(sumY2); if (denominator == 0.0) { // One or both parties has -all- the same ratings; // can't really say much similarity under this measure return Double.NaN; } return sumXY / denominator; } 继承AbstractItemSimilarity并实现AbstractItemSimilarity的类 以下这些类用于无偏好值的用户行为数据。 1.TanimotoCoefficientSimilarity 基于谷本系数的相似度:userID1的偏好物品与userID2的偏好物品的交集size/并集size(item与其类似),代码如下: public double userSimilarity(long userID1, long userID2) throws TasteException { DataModel dataModel = getDataModel(); FastIDSet xPrefs = dataModel.getItemIDsFromUser(userID1); FastIDSet yPrefs = dataModel.getItemIDsFromUser(userID2); int xPrefsSize = xPrefs.size(); int yPrefsSize = yPrefs.size(); if (xPrefsSize == 0 && yPrefsSize == 0) { return Double.NaN; } if (xPrefsSize == 0 || yPrefsSize == 0) { return 0.0; } //计算交集的size int intersectionSize = xPrefsSize < yPrefsSize ? yPrefs.intersectionSize(xPrefs) : xPrefs.intersectionSize(yPrefs); if (intersectionSize == 0) { return Double.NaN; } //计算并集size int unionSize = xPrefsSize + yPrefsSize - intersectionSize; return (double) intersectionSize / (double) unionSize; } 2.LogLikelihoodSimilarity 基于对数似然的相似度:基于谷本系数的相似度的升级版,代码如下: public double userSimilarity(long userID1, long userID2) throws TasteException { DataModel dataModel = getDataModel(); FastIDSet prefs1 = dataModel.getItemIDsFromUser(userID1); FastIDSet prefs2 = dataModel.getItemIDsFromUser(userID2); long prefs1Size = prefs1.size(); long prefs2Size = prefs2.size(); //计算交集size long intersectionSize = prefs1Size < prefs2Size ? prefs2.intersectionSize(prefs1) : prefs1.intersectionSize(prefs2); if (intersectionSize == 0) { return Double.NaN; } long numItems = dataModel.getNumItems(); double logLikelihood = LogLikelihood.logLikelihoodRatio(intersectionSize, prefs2Size - intersectionSize, prefs1Size - intersectionSize, numItems - prefs1Size - prefs2Size + intersectionSize); return 1.0 - 1.0 / (1.0 + logLikelihood); } 3.CityBlockSimilarity 基于街区距离的相似度,代码如下: public double userSimilarity(long userID1, long userID2) throws TasteException { DataModel dataModel = getDataModel(); FastIDSet prefs1 = dataModel.getItemIDsFromUser(userID1); FastIDSet prefs2 = dataModel.getItemIDsFromUser(userID2); int prefs1Size = prefs1.size(); int prefs2Size = prefs2.size(); int intersectionSize = prefs1Size < prefs2Size ? prefs2.intersectionSize(prefs1) : prefs1.intersectionSize(prefs2); return doSimilarity(prefs1Size, prefs2Size, intersectionSize); } //Calculate City Block Distance from total non-zero values and intersections and map to a similarity value. private static double doSimilarity(int pref1, int pref2, int intersection) { int distance = pref1 + pref2 - 2 * intersection; return 1.0 / (1.0 + distance); } 只继承AbstractItemSimilarity的实现类 1.TrackItemSimilarity 代码如下: public double itemSimilarity(long itemID1, long itemID2) { if (itemID1 == itemID2) { return 1.0; } TrackData data1 = trackData.get(itemID1); TrackData data2 = trackData.get(itemID2); if (data1 == null || data2 == null) { return 0.0; } // Arbitrarily decide that same album means "very similar" if (data1.getAlbumID() != TrackData.NO_VALUE_ID && data1.getAlbumID() == data2.getAlbumID()) { return 0.9; } // ... and same artist means "fairly similar" if (data1.getArtistID() != TrackData.NO_VALUE_ID && data1.getArtistID() == data2.getArtistID()) { return 0.7; } // Tanimoto coefficient similarity based on genre, but maximum value of 0.25 FastIDSet genres1 = data1.getGenreIDs(); FastIDSet genres2 = data2.getGenreIDs(); if (genres1 == null || genres2 == null) { return 0.0; } int intersectionSize = genres1.intersectionSize(genres2); if (intersectionSize == 0) { return 0.0; } int unionSize = genres1.size() + genres2.size() - intersectionSize; return (double) intersectionSize / (4.0 * unionSize); } 2.HybridSimilarity 基于混合的相似度计算:LogLikelihoodSimilarity*TrackItemSimilarity。代码如下: HybridSimilarity(DataModel dataModel, File dataFileDirectory) throws IOException { super(dataModel); cfSimilarity = new LogLikelihoodSimilarity(dataModel); contentSimilarity = new TrackItemSimilarity(dataFileDirectory); } public double itemSimilarity(long itemID1, long itemID2) throws TasteException { return contentSimilarity.itemSimilarity(itemID1, itemID2) * cfSimilarity.itemSimilarity(itemID1, itemID2); }
分布式爬虫架构 经过新一轮的投票,项目的范围已经基本确定。 大家决定 全力以付,集中攻克“分布式爬虫”。 分布式爬虫架构1 使用队列,即生产者,消费都模式。 由于生产者将规则生成到队列,然后由爬虫集群(消费者)到队列中取规则,然后按优先级等规则进行爬取。 分布式爬虫架构2 类似于webmagic,webmagic的是一个无须配置、便于二次开发的爬虫框架,它提供简单灵活的API,只需少量代码即可实现一个爬虫。webmagic采用完全模块化的设计,功能覆盖整个爬虫的生命周期(链接提取、页面下载、内容抽取、持久化),支持多线程抓取,分布式抓取,并支持自动重试、自定义UA/cookie等功能。 分布式爬虫架构3 分布式爬虫架构3,参考的Cola是一个分布式的爬虫框架,用户只需编写几个特定的函数,而无需关注分布式运行的细节。任务会自动分配到多台机器上,整个过程对用户是透明的。 基于Cola实现的爬虫位于contrib/目录下。目前实现了四个爬虫: wiki:维基百科。 weibo:新浪微博爬虫。从初始用户出发,然后是其关注和粉丝,依次类推,抓取指定个数的新浪微博用户的微博、个人信息、关注和粉丝。其中,用户微博只获取了内容、赞的个数、转发和评论的个数等等,而没有具体去获取此微博被转发和评论的内容。 generic(unstable):通用爬虫,只需配置,而无需修改代码。目前Cola实现了一个抽取器(cola/core /extractor),能够从网页正文中自动抽取主要内容,即去除类似边栏和底脚等内容。但是,此抽取器目前准确度还不够,效率也不够高,所以需要谨慎 使用。 weibosearch(unstable):新浪微博搜索的爬虫。这个爬虫使用 cola.core.opener.SpynnerOpener,基于spynner实现了一个Opener能够执行JavaScript和Ajax代 码。目前这个爬虫存在的问题是:新浪微博可能会将其识别成机器人,因此有可能会让输入验证码。 wiki和weibo之前有所提及。主要说明generic和weibosearch。 分布式爬虫架构4 设计方式参考hadoop等分布式运算架构。 控制结点类似于hadoop的namenode,工作结点类似于datanode。存储可以根据代理适配到DB或者Mongo集群等。 有想参与的可以一起进来讨论 群号 194338168 想深度参与的加,不想参与的就别往里进了,现在需要的主要是开发和文档两类人。群会定期往出清人! (项目会开源出来)
文档分享流程 今天在群里与大家讨论,想一个比较合理的分享流程。 我想看到流程应该是挺清楚了,就不再多加文字方面的解释了! 有想参与的可以一起进来讨论 群号 194338168 想深度参与的加,不想参与的就别往里进了,现在需要的主要是开发和文档两类人。群会定期往出清人! (项目会开源出来)
C4.5简介 C4.5是一系列用在机器学习和数据挖掘的分类问题中的算法。它的目标是监督学习:给定一个数据集,其中的每一个元组都能用一组属性值来描述,每一个元组属于一个互斥的类别中的某一类。C4.5的目标是通过学习,找到一个从属性值到类别的映射关系,并且这个映射能用于对新的类别未知的实体进行分类。 由于ID3算法在实际应用中存在一些问题,于是Quinlan提出了C4.5算法,严格上说C4.5只能是ID3的一个改进算法。 C4.5算法继承了ID3算法的优点,并在以下几方面对ID3算法进行了改进: 1) 用信息增益率来选择属性,克服了用信息增益选择属性时偏向选择取值多的属性的不足; 2) 在树构造过程中进行剪枝; 3) 能够完成对连续属性的离散化处理; 4) 能够对不完整数据进行处理。 C4.5算法有如下优点:产生的分类规则易于理解,准确率较高。其缺点是:在构造树的过程中,需要对数据集进行多次的顺序扫描和排序,因而导致算法的低效。此外,C4.5只适合于能够驻留于内存的数据集,当训练集大得无法在内存容纳时程序无法运行。 C4.5的分类器示意图 我们以一个很典型被引用过多次的训练数据集D为例,来说明C4.5算法如何计算信息增益并选择决策结点。 由其中四个属性来决定是否进行活动还是取消活动。上面的训练集有4个属性,即属性集合A={OUTLOOK, TEMPERATURE, HUMIDITY, WINDY};而类标签有2个,即类标签集合C={Yes, No},分别表示适合户外运动和不适合户外运动,其实是一个二分类问题。 C4.5的优缺点及算法流程 C4.5算法的优点是:产生的分类规则易于理解,准确率较高。 C4.5算法的缺点是:在构造树的过程中,需要对数据集进行多次的顺序扫描和排序,因而导致算法的低效。 C4.5的算法流程: DEMO示例 算法测试: https://github.com/zongtui/zongtui-Algorithm-test
什么是数据仓库? 数据仓库是一个面向主题的( Subject Oriented) 、集成的( Integrate) 、相对稳定的(NonVolatile) 、反映历史变化( Time Variant)的数据集合,用于支持管理决策。对于数据仓库的概念我们可以从两个层次予以理: ①数据仓库用于支持决策,面向分析型数据处理,它不同于企业现有的操作型数据库; ②数据仓库是对多个异构数据源的有效集成,集成后按照主题进行了重组,并包含历史数据,而且存放在数据仓库中的数据一般不再修改。 企业数据仓库的建设是以现有企业业务系统和大量业务数据的积累为基础。数据仓库不是静态的概念,只有把信息及时交给需要这些信息的使用者,供他们作出改善其业务经营的决策,信息才能发挥作用,信息才有意义。而把信息加以整理、归纳和重组,并及时提供给相应的管理决策人员是数据仓库的根本任务。 数据立方体与OLAP 数据立斱体以多维对数据迚行建模和观察。 下图就是客户、产品和销售的数据立方体: OLAP的多维分析操作包括:钻取(Drill-down)、上卷(Roll-up)、切片(Slice)、切块(Dice)以及旋转(Pivot)等。 钻取(Drill-down):在维的不同层次间的变化,从上层降到下一层,或者说是将汇总数据拆分到更细节的数据,比如通过对2010年第二季度的总销售数据进行钻取来查看2010年第二季度4、5、6每个月的消费数据。 上卷(Roll-up):钻取的逆操作,即从细粒度数据向高层的聚合,如将江苏省、上海市和浙江省的销售数据进行汇总来查看江浙沪地区的销售数据。 切片(Slice):选择维中特定的值进行分析,比如只选择电子产品的销售数据,或者2010年第二季度的数据。 切块(Dice):选择维中特定区间的数据或者某批特定值进行分析,比如选择2010年第一季度到2010年第二季度的销售数据,或者是电子产品和日用品的销售数据。 旋转(Pivot):即维的位置的互换,就像是二维表的行列转换,如图中通过旋转实现产品维和地域维的互换。 数据挖掘解决的四大类问题 1、分类 分类技术在很多领域都有应用,例如可以通过客户分类构造一个分类模型来对银行贷款进行风险评估;当前的市场营销中很重要的一个特点是强调客户细分。客户类别分析的功能也在于此,采用数据挖掘中的分类技术,可以将客户分成不同的类别,比如呼叫中心设计时可以分为:呼叫频繁的客户、偶然大量呼叫的客户、稳定呼叫的客户、其他,帮助呼叫中心寻找出这些不同种类客户之间的特征,这样的分类模型可以让用户了解不同行为类别客户的分布特征;其他分类应用如文献检索和搜索引擎中的自动文本分类技术;安全领域有基于分类技术的入侵检测等等。机器学习、专家系统、统计学和神经网络等领域的研究人员已经提出了许多具体的分类预测方法。下面对分类流程作个简要描述: 训练:训练集——>特征选取——>训练——>分类器 分类:新样本——>特征选取——>分类——>判决 下面看一个基于决策树的分类器的示例: 2、聚类 聚类:将数据对象划分为若干类,同一类的对象具有较高的相似度,不同类的对象相似度较低。从这个简单的描述中,可以看出聚类的关键是如何度量对象间的相似性。较为常见的用于度量对象的相似度的方法有距离、密度等。 聚类分析的原理可以根据下图来看: 对牌进行分组: 按花色分: 按符号分: 按颜色分: 按大小程度相近分: 下面就是一个聚类的示例: 3、预测 数据挖掘预测与周易预测有相似之处。周易建立在阴阳二元论基础上,对天地万物进行性状归类(天干地支五行论),精确到可以对事物的未来发展做出较为准确的预测。许多学者认为周易理论依据是万事万物的相似性、关联性和全息性原理。这三个原理已被现代科学所证实。全息性是指事物的某一局部包含了整体的信息。例如,法医工作者对一根毛发进行化验,得出受害者或嫌疑人的许多身体特征。 周易预测通过对历史事件的学习来积累经验,得出事物间的相似性和关联性,从而对事物的未来状况做出预测。数据挖掘预测则是通过对样本数据(历史数据)的输入值和输出值关联性的学习,得到预测模型,再利用该模型对未来的输入值进行输出值预测。一般地,可以通过机器学习方法建立预测模型。DM(Data Mining)的技术基础是人工智能(机器学习),但是DM仅仅利用了人工智能(AI)中一些已经成熟的算法和技术,因而复杂度和难度都比AI小很多。 机器学习:假定事物的输入、输出之间存在一种函数关系y=f(x, β),其中β是待定参数,x是输入变量,则y=f(x, β)称为学习机器。通过数据建模,由样本数据(一般是历史数据,包含输入值和输出值)学习得到参数β的取值,就确定了具体表达式y=f(x, β),这样就可以对新的x预测y了。这个过程称作机器学习。 数据建模不同于数学建模,它是基于数据建立数学模型,它是相对于基于物理、化学和其他专业基本原理建立数学模型(即机理建模)而言的。对于预测来说,如果所研究的对象有明晰的机理,可以依其进行数学建模,这当然是最好的选择。但是实际问题中,一般无法进行机理建模。但是历史数据往往是容易获得的,这时就可使用数据建模。 典型的机器学习方法包括:决策树方法、人工神经网络、支持向量机、正则化方法。其他常见的预测方法还有近邻法、朴素贝叶斯(属于统计学习方法)等。 预测的模型可以参考下图: 4、关联 分析各个物品或者商品之间同时出现的机率。 在各种数据挖掘算法中,关联规则挖掘算是比较重要的一种,尤其是受购物篮分析的影响,关联规则被应用到很多实际业务中。 首先,和聚类算法一样,关联规则挖掘属于无监督学习方法,它描述的是在一个事物中物品间同时出现的规律的知识模式,现实生活中,比如超市购物时,顾客购买记录常常隐含着很多关联规则,比如购买圆珠笔的顾客中有65%也购买了笔记本,利用这些规则,商场人员可以很好的规划商品摆放问题。在电商网站中,利用关联规则可以发现哪些用户更喜欢哪类的商品,当发现有类似的客户的时候,可以将其它客户购买的商品推荐给相类似的客户,以提高网站的收入。 下图就是一个关联的示例: CRISP-DM CRISP-DM 模型为一个KDD工程提供了一个完整的过程描述.该模型将一个KDD工程分为6个不同的,但顺序并非完全不变的阶段。 1: business understanding: 即商业理解. 在第一个阶段我们必须从商业的角度上面了解项目的要求和最终目的是什么. 并将这些目的与数据挖掘的定义以及结果结合起来。 2: data understanding: 数据的理解以及收集,对可用的数据进行评估。 3: data preperation: 数据的准备,对可用的原始数据进行一系列的组织以及清洗,使之达到建模需求。 4: modeling: 即应用数据挖掘工具建立模型。 5: evaluation: 对建立的模型进行评估,重点具体考虑得出的结果是否符合第一步的商业目的。 6: deployment: 部署(方案实施),即将其发现的结果以及过程组织成为可读文本形式.(数据挖掘报告)。 商业理解(Business understanding):商业理解阶段应算是数据挖掘中最重要的一个部分,在这个阶段里我们需要明确商业目标、评估商业环境、确定挖掘目标以及产生一个项目计划。 数据理解(Data understanding):数据是我们挖掘过程的“原材料”,在数据理解过程中我们要知道都有些什么数据,这些数据的特征是什么,可以通过对数据的描述性分析得到数据的特点。 数据准备(Date preparation):在数据准备阶段我们需要对数据作出选择、清洗、重建、合并等工作。选出要进行分析的数据,并对不符合模型输入要求的数据进行规范化操作。 建模(Modeling):建模过程也是数据挖掘中一个比较重要的过程。我们需要根据分析目的选出适合的模型工具,通过样本建立模型并对模型进行评估。 模型评估(Evaluation):并不是每一次建模都能与我们的目的吻合,评价阶段旨在对建模结果进行评估,对效果较差的结果我们需要分析原因,有时还需要返回前面的步骤对挖掘过程重新定义。 结果部署(Deployment):这个阶段是用建立的模型去解决实际中遇到的问题,它还包括了监督、维持、产生最终报表、重新评估模型等过程。 总结 以上分别介绍了数据仓库和数据立方体,并且介绍了数据挖掘要解决的四大类问题,任何跟数据挖掘相关的问题都可以先归类到这四大类问题中,然后再根据相应的算法进行解决。 最后介绍了CRISP-DM 模型,是IBM提出的标准模型,可以对数据挖掘的过程进行理论的指导。在接下来会针对用户产生的数据来探讨如何进行用户画像。
网站数据统计分析工具是网站站长和运营人员经常使用的一种工具,比较常用的有谷歌分析、百度统计和腾讯分析等等。所有这些统计分析工具的第一步都是网站访问数据的收集。目前主流的数据收集方式基本都是基于javascript的。本文将简要分析这种数据收集的原理,并一步一步实际搭建一个实际的数据收集系统。 数据收集原理分析 简单来说,网站统计分析工具需要收集到用户浏览目标网站的行为(如打开某网页、点击某按钮、将商品加入购物车等)及行为附加数据(如某下单行为产生的订单金额等)。早期的网站统计往往只收集一种用户行为:页面的打开。而后用户在页面中的行为均无法收集。这种收集策略能满足基本的流量分析、来源分析、内容分析及访客属性等常用分析视角,但是,随着ajax技术的广泛使用及电子商务网站对于电子商务目标的统计分析的需求越来越强烈,这种传统的收集策略已经显得力不能及。 后来,Google在其产品谷歌分析中创新性的引入了可定制的数据收集脚本,用户通过谷歌分析定义好的可扩展接口,只需编写少量的javascript代码就可以实现自定义事件和自定义指标的跟踪和分析。目前百度统计、搜狗分析等产品均照搬了谷歌分析的模式。 其实说起来两种数据收集模式的基本原理和流程是一致的,只是后一种通过javascript收集到了更多的信息。下面看一下现在各种网站统计工具的数据收集基本原理。 流程概览 首先通过一幅图总体看一下数据收集的基本流程。 图1. 网站统计数据收集基本流程 首先,用户的行为会触发浏览器对被统计页面的一个http请求,这里姑且先认为行为就是打开网页。当网页被打开,页面中的埋点javascript片段会被执行,用过相关工具的朋友应该知道,一般网站统计工具都会要求用户在网页中加入一小段javascript代码,这个代码片段一般会动态创建一个script标签,并将src指向一个单独的js文件,此时这个单独的js文件(图1中绿色节点)会被浏览器请求到并执行,这个js往往就是真正的数据收集脚本。数据收集完成后,js会请求一个后端的数据收集脚本(图1中的backend),这个脚本一般是一个伪装成图片的动态脚本程序,可能由php、python或其它服务端语言编写,js会将收集到的数据通过http参数的方式传递给后端脚本,后端脚本解析参数并按固定格式记录到访问日志,同时可能会在http响应中给客户端种植一些用于追踪的cookie。 上面是一个数据收集的大概流程,下面以谷歌分析为例,对每一个阶段进行一个相对详细的分析。 埋点脚本执行阶段 若要使用谷歌分析(以下简称GA),需要在页面中插入一段它提供的javascript片段,这个片段往往被称为埋点代码。下面是我的博客中所放置的谷歌分析埋点代码截图: 图2. 谷歌分析埋点代码 其中_gaq是GA的的全局数组,用于放置各种配置,其中每一条配置的格式为: _gaq.push(['Action', 'param1', 'param2', ...]); Action指定配置动作,后面是相关的参数列表。GA给的默认埋点代码会给出两条预置配置,_setAccount用于设置网站标识ID,这个标识ID是在注册GA时分配的。_trackPageview告诉GA跟踪一次页面访问。更多配置请参考:https://developers.google.com/analytics/devguides/collection/gajs/。实际上,这个_gaq是被当做一个FIFO队列来用的,配置代码不必出现在埋点代码之前,具体请参考上述链接的说明。 就本文来说,_gaq的机制不是重点,重点是后面匿名函数的代码,这才是埋点代码真正要做的。这段代码的主要目的就是引入一个外部的js文件(ga.js),方式是通过document.createElement方法创建一个script并根据协议(http或https)将src指向对应的ga.js,最后将这个element插入页面的dom树上。 注意ga.async = true的意思是异步调用外部js文件,即不阻塞浏览器的解析,待外部js下载完成后异步执行。这个属性是HTML5新引入的。 数据收集脚本执行阶段 数据收集脚本(ga.js)被请求后会被执行,这个脚本一般要做如下几件事: 1、通过浏览器内置javascript对象收集信息,如页面title(通过document.title)、referrer(上一跳url,通过document.referrer)、用户显示器分辨率(通过windows.screen)、cookie信息(通过document.cookie)等等一些信息。 2、解析_gaq收集配置信息。这里面可能会包括用户自定义的事件跟踪、业务数据(如电子商务网站的商品编号等)等。 3、将上面两步收集的数据按预定义格式解析并拼接。 4、请求一个后端脚本,将信息放在http request参数中携带给后端脚本。 这里唯一的问题是步骤4,javascript请求后端脚本常用的方法是ajax,但是ajax是不能跨域请求的。这里ga.js在被统计网站的域内执行,而后端脚本在另外的域(GA的后端统计脚本是http://www.google-analytics.com/__utm.gif),ajax行不通。一种通用的方法是js脚本创建一个Image对象,将Image对象的src属性指向后端脚本并携带参数,此时即实现了跨域请求后端。这也是后端脚本为什么通常伪装成gif文件的原因。通过http抓包可以看到ga.js对__utm.gif的请求: 图3. 后端脚本请求的http包 可以看到ga.js在请求__utm.gif时带了很多信息,例如utmsr=1280×1024是屏幕分辨率,utmac=UA-35712773-1是_gaq中解析出的我的GA标识ID等等。 值得注意的是,__utm.gif未必只会在埋点代码执行时被请求,如果用_trackEvent配置了事件跟踪,则在事件发生时也会请求这个脚本。 由于ga.js经过了压缩和混淆,可读性很差,我们就不分析了,具体后面实现阶段我会实现一个功能类似的脚本。 后端脚本执行阶段 GA的__utm.gif是一个伪装成gif的脚本。这种后端脚本一般要完成以下几件事情: 1、解析http请求参数的到信息。 2、从服务器(WebServer)中获取一些客户端无法获取的信息,如访客ip等。 3、将信息按格式写入log。 5、生成一副1×1的空gif图片作为响应内容并将响应头的Content-type设为image/gif。 5、在响应头中通过Set-cookie设置一些需要的cookie信息。 之所以要设置cookie是因为如果要跟踪唯一访客,通常做法是如果在请求时发现客户端没有指定的跟踪cookie,则根据规则生成一个全局唯一的cookie并种植给用户,否则Set-cookie中放置获取到的跟踪cookie以保持同一用户cookie不变(见图4)。 图4. 通过cookie跟踪唯一用户的原理 这种做法虽然不是完美的(例如用户清掉cookie或更换浏览器会被认为是两个用户),但是是目前被广泛使用的手段。注意,如果没有跨站跟踪同一用户的需求,可以通过js将cookie种植在被统计站点的域下(GA是这么做的),如果要全网统一定位,则通过后端脚本种植在服务端域下(我们待会的实现会这么做)。 系统的设计实现 根据上述原理,我自己搭建了一个访问日志收集系统。总体来说,搭建这个系统要做如下的事: 图5. 访问数据收集系统工作分解 下面详述每一步的实现。我将这个系统叫做MyAnalytics。 确定收集的信息 为了简单起见,我不打算实现GA的完整数据收集模型,而是收集以下信息。 名称 途径 备注 访问时间 web server Nginx $msec IP web server Nginx $remote_addr 域名 javascript document.domain URL javascript document.URL 页面标题 javascript document.title 分辨率 javascript window.screen.height & width 颜色深度 javascript window.screen.colorDepth Referrer javascript document.referrer 浏览客户端 web server Nginx $http_user_agent 客户端语言 javascript navigator.language 访客标识 cookie 网站标识 javascript 自定义对象 埋点代码 埋点代码我将借鉴GA的模式,但是目前不会将配置对象作为一个FIFO队列用。一个埋点代码的模板如下: <script type=”text/javascript”>// <![CDATA[ var _maq = _maq || []; _maq.push(['_setAccount', '网站标识']); (function() { var ma = document.createElement(‘script’); ma.type = ‘text/javascript'; ma.async = true; ma.src = (‘https:’ == document.location.protocol ? ‘https://analytics’ : ‘http://analytics’) + ‘.codinglabs.org/ma.js'; var s = document.getElementsByTagName(‘script’)[0]; s.parentNode.insertBefore(ma, s); })(); // ]]></script> 这里我启用了二级域名analytics.codinglabs.org,统计脚本的名称为ma.js。当然这里有一点小问题,因为我并没有https的服务器,所以如果一个https站点部署了代码会有问题,不过这里我们先忽略吧。 前端统计脚本 我写了一个不是很完善但能完成基本工作的统计脚本ma.js: (function () { var params = {}; //Document对象数据 if(document) { params.domain = document.domain || ”; params.url = document.URL || ”; params.title = document.title || ”; params.referrer = document.referrer || ”; } //Window对象数据 if(window &amp;&amp; window.screen) { params.sh = window.screen.height || 0; params.sw = window.screen.width || 0; params.cd = window.screen.colorDepth || 0; } //navigator对象数据 if(navigator) { params.lang = navigator.language || ”; } //解析_maq配置 if(_maq) { for(var i in _maq) { switch(_maq[i][0]) { case ‘_setAccount': params.account = _maq[i][1]; break; default: break; } } } //拼接参数串 var args = ”; for(var i in params) { if(args != ”) { args += ‘&amp;'; } args += i + ‘=’ + encodeURIComponent(params[i]); } //通过Image对象请求后端脚本 var img = new Image(1, 1); img.src = ‘http://analytics.codinglabs.org/1.gif?’ + args; })(); 整个脚本放在匿名函数里,确保不会污染全局环境。功能在原理一节已经说明,不再赘述。其中1.gif是后端脚本。 日志格式 日志采用每行一条记录的方式,采用不可见字符^A(ascii码0x01,Linux下可通过ctrl + v ctrl + a输入,下文均用“^A”表示不可见字符0x01),具体格式如下: 时间^AIP^A域名^AURL^A页面标题^AReferrer^A分辨率高^A分辨率宽^A颜色深度^A语言^A客户端信息^A用户标识^A网站标识 后端脚本 为了简单和效率考虑,我打算直接使用nginx的access_log做日志收集,不过有个问题就是nginx配置本身的逻辑表达能力有限,所以我选用了OpenResty做这个事情。OpenResty是一个基于Nginx扩展出的高性能应用开发平台,内部集成了诸多有用的模块,其中的核心是通过ngx_lua模块集成了Lua,从而在nginx配置文件中可以通过Lua来表述业务。关于这个平台我这里不做过多介绍,感兴趣的同学可以参考其官方网站http://openresty.org/,或者这里有其作者章亦春(agentzh)做的一个非常有爱的介绍OpenResty的slide:http://agentzh.org/misc/slides/ngx-openresty-ecosystem/,关于ngx_lua可以参考:https://github.com/chaoslawful/lua-nginx-module。 首先,需要在nginx的配置文件中定义日志格式: log_format tick “$msec^A$remote_addr^A$u_domain^A$u_url^A$u_title^A$u_referrer^A$u_sh^A$u_sw^A$u_cd^A$u_lang^A$http_user_agent^A$u_utrace^A$u_account”; 注意这里以u_开头的是我们待会会自己定义的变量,其它的是nginx内置变量。 然后是核心的两个location: location /1.gif { #伪装成gif文件 default_type image/gif; #本身关闭access_log,通过subrequest记录log access_log off; access_by_lua ” — 用户跟踪cookie名为__utrace local uid = ngx.var.cookie___utrace if not uid then — 如果没有则生成一个跟踪cookie,算法为md5(时间戳+IP+客户端信息) uid = ngx.md5(ngx.now() .. ngx.var.remote_addr .. ngx.var.http_user_agent) end ngx.header['Set-Cookie'] = {‘__utrace=’ .. uid .. ‘; path=/’} if ngx.var.arg_domain then — 通过subrequest到/i-log记录日志,将参数和用户跟踪cookie带过去 ngx.location.capture(‘/i-log?’ .. ngx.var.args .. ‘&utrace=’ .. uid) end “; #此请求不缓存 add_header Expires “Fri, 01 Jan 1980 00:00:00 GMT”; add_header Pragma “no-cache”; add_header Cache-Control “no-cache, max-age=0, must-revalidate”; #返回一个1×1的空gif图片 empty_gif; } location /i-log { #内部location,不允许外部直接访问 internal; #设置变量,注意需要unescape set_unescape_uri $u_domain $arg_domain; set_unescape_uri $u_url $arg_url; set_unescape_uri $u_title $arg_title; set_unescape_uri $u_referrer $arg_referrer; set_unescape_uri $u_sh $arg_sh; set_unescape_uri $u_sw $arg_sw; set_unescape_uri $u_cd $arg_cd; set_unescape_uri $u_lang $arg_lang; set_unescape_uri $u_utrace $arg_utrace; set_unescape_uri $u_account $arg_account; #打开日志 log_subrequest on; #记录日志到ma.log,实际应用中最好加buffer,格式为tick access_log /path/to/logs/directory/ma.log tick; #输出空字符串 echo ”; } 要完全解释这段脚本的每一个细节有点超出本文的范围,而且用到了诸多第三方ngxin模块(全都包含在OpenResty中了),重点的地方我都用注释标出来了,可以不用完全理解每一行的意义,只要大约知道这个配置完成了我们在原理一节提到的后端逻辑就可以了。 日志轮转 真正的日志收集系统访问日志会非常多,时间一长文件变得很大,而且日志放在一个文件不便于管理。所以通常要按时间段将日志切分,例如每天或每小时切分一个日志。我这里为了效果明显,每一小时切分一个日志。我是通过crontab定时调用一个shell脚本实现的,shell脚本如下: _prefix=”/path/to/nginx” time=`date +%Y%m%d%H` mv ${_prefix}/logs/ma.log ${_prefix}/logs/ma/ma-${time}.log kill -USR1 `cat ${_prefix}/logs/nginx.pid` 这个脚本将ma.log移动到指定文件夹并重命名为ma-{yyyymmddhh}.log,然后向nginx发送USR1信号令其重新打开日志文件。 然后再/etc/crontab里加入一行: 59 * * * * root /path/to/directory/rotatelog.sh 在每个小时的59分启动这个脚本进行日志轮转操作。 测试 下面可以测试这个系统是否能正常运行了。我昨天就在我的博客中埋了相关的点,通过http抓包可以看到ma.js和1.gif已经被正确请求: 图6. http包分析ma.js和1.gif的请求 同时可以看一下1.gif的请求参数: 图7. 1.gif的请求参数 相关信息确实也放在了请求参数中。 然后我tail打开日志文件,然后刷新一下页面,因为没有设access log buffer, 我立即得到了一条新日志: 1351060731.360^A0.0.0.0^Awww.codinglabs.org^Ahttp://www.codinglabs.org/^ACodingLabs^A^A1024^A1280^A24^Azh-CN^AMozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4^A4d612be64366768d32e623d594e82678^AU-1-1 注意实际上原日志中的^A是不可见的,这里我用可见的^A替换为方便阅读,另外IP由于涉及隐私我替换为了0.0.0.0。 看一眼日志轮转目录,由于我之前已经埋了点,所以已经生成了很多轮转文件: 图8. 轮转日志 关于分析 通过上面的分析和开发可以大致理解一个网站统计的日志收集系统是如何工作的。有了这些日志,就可以进行后续的分析了。本文只注重日志收集,所以不会写太多关于分析的东西。 注意,原始日志最好尽量多的保留信息而不要做过多过滤和处理。例如上面的MyAnalytics保留了毫秒级时间戳而不是格式化后的时间,时间的格式化是后面的系统做的事而不是日志收集系统的责任。后面的系统根据原始日志可以分析出很多东西,例如通过IP库可以定位访问者的地域、user agent中可以得到访问者的操作系统、浏览器等信息,再结合复杂的分析模型,就可以做流量、来源、访客、地域、路径等分析了。当然,一般不会直接对原始日志分析,而是会将其清洗格式化后转存到其它地方,如MySQL或HBase中再做分析。 分析部分的工作有很多开源的基础设施可以使用,例如实时分析可以使用Storm,而离线分析可以使用Hadoop。当然,在日志比较小的情况下,也可以通过shell命令做一些简单的分析,例如,下面三条命令可以分别得出我的博客在今天上午8点到9点的访问量(PV),访客数(UV)和独立IP数(IP): awk -F^A ‘{print $1}’ ma-2012102409.log | wc -l awk -F^A ‘{print $12}’ ma-2012102409.log | uniq | wc -l awk -F^A ‘{print $2}’ ma-2012102409.log | uniq | wc -l 其它好玩的东西朋友们可以慢慢挖掘。 参考 GA的开发者文档:https://developers.google.com/analytics/devguides/collection/gajs/ 一篇关于实现nginx收日志的文章:http://blog.linezing.com/2011/11/%E4%BD%BF%E7%94%A8nginx%E8%AE%B0%E6%97%A5%E5%BF%97 关于Nginx可以参考:http://wiki.nginx.org/Main OpenResty的官方网站为:http://openresty.org ngx_lua模块可参考:https://github.com/chaoslawful/lua-nginx-module 本文http抓包使用Chrome浏览器开发者工具,绘制思维导图使用Xmind,流程和结构图使用Tikz PGF 转自:http://blog.codinglabs.org/articles/how-web-analytics-data-collection-system-work.html
收集web日志的目的 Web日志挖掘是指采用数据挖掘技术,对站点用户访问Web服务器过程中产生的日志数据进行分析处理,从而发现Web用户的访问模式和兴趣爱好等,这些信息对站点建设潜在有用的可理解的未知信息和知识,用于分析站点的被访问情况,辅助站点管理和决策支持等。 1、以改进web站点设计为目标,通过挖掘用户聚类和用户的频繁访问路径,修改站点的页面之间的链接关系,以适应用户的访问习惯,并且同时为用户提供有针对性的电子商务活动和个性化的信息服务,应用信息推拉技术构建智能化Web站点。 2、以分析Web站点性能为目标,主要从统计学的角度,对日志数据项进行粗略的统计分析,得到用户频繁访问页、单位时间的访问数、访问数量随时间分布图等。现有的绝大多数的Web日志分析工具都属于此类。 3、以理解用户意图为目标,主要是通过与用户交互的过程收集用户的信息,Web服务器根据这些信息对用户请求的页面进行裁剪,为用户返回定制的页面,其目的就是提高用户的满意度和提供个性化的服务。 收集方式 网站分析数据主要有三种收集方式:Web日志、JavaScript标记和包嗅探器。 1. Web日志 web日志处理流程: 从上图可以看出网站分析数据的收集从网站访问者输入URL向网站服务器发出http请求就开始了。网站服务器接收到请求后会在自己的Log文件中追加一条记录,记录内容包括:远程主机名(或者是IP地址)、登录名、登录全名、发请求的日期、发请求的时间、请求的详细(包括请求的方法、地址、协议)、请求返回的状态、请求文档的大小。随后网站服务器将页面返回到访问者的浏览器内得以展现。 2. JavaScript标记 JavaScript标记处理流程: 上图所示JavaScript标记同Web日志收集数据一样,从网站访问者发出http请求开始。不同的是,JavaScript标记返回给访问者的网页代码中会包含一段特殊的JavaScript代码,当页面展示的同时这段代码也得以执行。这段代码会从访问者的Cookie中取得详细信息(访问时间、浏览器信息、工具厂商赋予当前访问者的userID等)并发送到工具商的数据收集服务器。数据收集服务器对收集到的数据处理后存入数据库中。网站经营人员通过访问分析报表系统查看这些数据。 3. 包嗅探器 通过包嗅探器收集分析的流程: 上图可以看出网站访问者发出的请求到达网站服务器之前,会先经过包嗅探器,然后包嗅探器才会将请求发送到网站服务器。包嗅探器收集到的数据经过工具厂商的处理服务器后存入数据库。随后网站经营人员就可以通过分析报表系统看到这些数据。 web日志挖掘过程 整体流程参考下图: 1、数据预处理阶段 根据挖掘的目的,对原始Web日志文件中的数据进行提取、分解、合并、最后转换为用户会话文件。该阶段是Web访问信息挖掘最关键的阶段,数据预处理包括:关于用户访问信息的预处理、关于内容和结构的预处理。 2、会话识别阶段 该阶段本是属于数据预处理阶段中的一部分,这里将其划分成单独的一个阶段,是因为把用户会话文件划分成的一组组用户会话序列将直接用于挖掘算法,它的精准度直接决定了挖掘结果的好坏,是挖掘过程中最重要的阶段。 3、模式发现阶段 模式发现是运用各种方法和技术从Web同志数据中挖掘和发现用户使用Web的各种潜在的规律和模式。模式发现使用的算法和方法不仅仅来自数据挖掘领域,还包括机器学习、统计学和模式识别等其他专业领域。 模式发现的主要技术有:统计分析(statistical analysis)、关联规则(association rules)、聚类(clustering)、归类(classification)、序列模式(sequential patterns)、依赖关系(dependency)。 (1)统计分析(statistical analysis):常用的统计技术有:贝叶斯定理、预测回归、对数回归、对数-线性回归等。可用来分析网页的访问频率,网页的访问时间、访问路径。可用于系统性能分析、发现安全漏洞、为网站修改、市场决策提供支持。 (2)关联规则(association rules):关联规则是最基本的挖掘技术,同时也是WUM最常用的方法。在WUM中常常用在被访问的网页中,这有利于优化网站组织、网站设计者、网站内容管理者和市场分析,通过市场分析可以知道哪些商品被频繁购买,哪些顾客是潜在顾客。 (3)聚类(clustering):聚类技术是在海量数据中寻找彼此相似对象组,这些数据基于距离函数求出对象组之间的相似度。在WUM中可以把具有相似模式的用户分成组,可以用于电子商务中市场分片和为用户提供个性化服务。 (4)归类(classification):归类技术主要用途是将用户资料归入某一特定类中,它与机器学习关系很紧密。可以用的技术有:决策树(decision tree)、K-最近邻居、Naïve Bayesian classifiers、支持向量机(support vector machines)。 (5)序列模式(sequential patterns):给定一个由不同序列组成的集合,其中,每个序列由不同的元素按顺序有序排列,每个元素由不同项目组成,同时给定一个用户指定的最小支持度阈值,序列模式挖掘就是找出所有的频繁子序列,即子序列在序列集中的出现频率不低于用户指定的最小支持度阈值。 (6)依赖关系(dependency):一个依赖关系存在于两个元素之间,如果一个元素A的值可以推出另一个元素B的值,则B依赖于A。 4、模式分析阶段 模式分析是Web使用挖掘最后一步,主要目的是过滤模式发现阶段产生的规则和模式,去除那些无用的模式,并把发现的模式通过一定的方法直观的表现出来。由于Web使用挖掘在大多数情况下属于无偏向学习,有可能挖掘出所有的模式和规则,所以不能排除其中有些模式是常识性的,普通的或最终用户不感兴趣的,故必须采用模式分析的方法使得挖掘出来的规则和知识具有可读性和最终可理解性。常见的模式分析方法有图形和可视化技术、数据库查询机制、数理统计和可用性分析等。 收集数据包括 收集的数据主要包括: 全局UUID、访问日期、访问时间、生成日志项的服务器的IP地址、客户端试图执行的操作、客户端访问的服务器资源、客户端尝试执行的查询、客户端连接到的端口号、访问服务器的已验证用户名称、发送服务器资源请求的客户端IP地址、客户端使用的操作系统、浏览器等信息、操作的状态码(200等)、子状态、用Windows@使用的术语表示的操作的状态、点击次数。 用户识别 对于网站的运营者来说,如何能够高效精确的识别用户非常关键,这会对网站运营带来极大的帮助,如定向推荐等。 用户识别方法如下: 使用HDFS存储 数据收集到服务器之后,根据数据量可以考虑将数据存储在hadoop的HDFS中。 如果不熟悉HDFS,可以参考: http://www.niubua.com/?p=1107 在现在的企业中,一般情况下都是多台服务器生成日志,日志包括nginx生成的,也包括在程序中使用log4j生成的自定义格式的。 通常的架构如下图: 使用mapreduce分析nginx日志 nginx默认的日志格式如下: 222.68.172.190 - - [18/Sep/2013:06:49:57 +0000] "GET /images/my.jpg HTTP/1.1" 200 19939 "http://www.angularjs.cn/A00n" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36" 变量的解释如下: remote_addr: 记录客户端的ip地址, 222.68.172.190 remote_user: 记录客户端用户名称, – time_local: 记录访问时间与时区, [18/Sep/2013:06:49:57 +0000] request: 记录请求的url与http协议, “GET /images/my.jpg HTTP/1.1″ status: 记录请求状态,成功是200, 200 body_bytes_sent: 记录发送给客户端文件主体内容大小, 19939 http_referer: 用来记录从那个页面链接访问过来的, “http://www.angularjs.cn/A00n” http_user_agent: 记录客户浏览器的相关信息, “Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36″ 可以直接使用mapreduce来进行日志分析: 在hadoop中计算后定时导入到关系型数据库中进行展现。 要明细的分析可以参考这篇: http://www.tuicool.com/articles/2ANJZz 也可以使用hive来代替mapreduce进行分析。 总结 web日志收集是每个互联网企业必须要处理的过程,当收集上来数据,并且通过适当的数据挖掘之后,会对整体网站的运营能力及网站的优化带来质的提升,真正的做到数据化分析和数据化运营。
1. 约会的底线在变 2. 社交的内容在变 3. 欲望在变 4. 选择在变 5. 原因在变 6. 朋友的态度在变 7. 对待朋友的态度也在变 8. 居家日常在变 9. 时间感在变 10. 睡眠也在变
2013年年底,奥维咨询(AVC)召开了大数据时代的战略规划发布会,在发布会上奥维咨询(AVC)董事长喻亮星做了关于三步走的战略:第一阶段是激活企业内部的冷数据,第二阶段是数据转化为资产,第三步是构建企业大数据竞争力。而现在的情况是:企业售后服务的数据以及官网的数据非常多,有很多值得深度挖掘。用户洞察的定义和目的 在构建大数据方面,现在各大企业都在进行探索。要构建大数据系统,首先要知道什么是用户洞察,标准的用户洞察包含三个步骤:用户的数据管理、用户的需求分析、分析以后建立用户洞察力的应用。 用户的数据包括:历史销售数据、用户评价数据、用户注册数据、用户保修数据、用户维修数据、用户社交数据。用户的需求分析即对用户信息的理解,并进行适应性的建模,通过动态的行为和价值分析,识别用户的行为、价值和需求。在用户数据管理与用户需求分析的基础上,策划、开发和提供蕴含用户实质需求的差异化产品、业务或营销方案,开展有针对性的营销和拓展市场。 因此用户洞察的目的就是通过已有的需求或者已经产生的交易行为记录,对这些用户进行分析,然后做精准营销或者挖掘潜在需求。用户画像模型分析 用户画像是用户洞察中最为关键的环节,比如说他是谁,他的消费能力如何,他过往的消费历史是什么,他的购物习惯和社交偏好是什么。通过简单的方式或者是非常有限的数据,就能够找到这些内容。奥维咨询(AVC)在研究中建立了108个用户标签的画像体系,这个体系基本涵盖了我们想要知道的内容,但是这些数据都是从动态数据里面获取的,甚至不需要公开的数据,而是通过曾经购买的行为推测出来他的标签或者是他的特征。 举例来说:如果她叫翠花,那么她是女生;如果他是给丈母娘买的,那么猜测他是男生;如果她在2012年10月份买了一段奶粉,2013年2月买了二段奶粉,那么可以推测她有孩子,并且孩子已经两岁半了;如果他买了高端的A.O史密斯热水器,那么他的消费能力相对比较强;如果一位用户关注科技,比如说可穿戴设备,那么他一定是科技达人;如果他买了净水器,他可能对空气净化器有要求。通过这些历史数据、SNS数据或者行为数据,探究同一个客户有没有二次购买的可能;如果他是优质的客户,有没有冲动购买的可能,这都是需要仔细研究的。基于交易数据的用户洞察 根据电商的交易数据对个人消费者用户进行分析,从消费内容的数据中洞悉该消费者的消费习惯和其他信息:根据用户消费能力级别数据可以了解消费者的消费能力;根据用户的购买次数分析其购物习惯,判定他是否是网购达人;根据用户的上网时间分布数据,分析消费者的职业、作息等信息;根据用户单次消费金额数据分析消费者的购买能力和收入状况等。 例如,一名消费者在2013年12月份到2014年4月份有五次消费,从他这五次交易的数据里面可以看到:他买了两次手机,还买了豆浆机、电视机;第一次购买手机的时候花了四千块,但第二次购买手机的时候只花了1950元。可以看出他热爱生活,是一个十足的数码控,消费能力很强,网购习惯很明显。当然这些数据不一定很准,但是也不需要它很准。只要能够做出画像就足够了。 通过分析,认识了他,知道他叫什么,也知道他在哪里,然后进行的就是用户洞察力的行为应用:电话他、短信他、邮件他、私信他,用打折、促销、返券、送积分、给链接、门店地址等方式吸引他、勾引他,全方位地缠绕他。这种全方位的营销到底能不能产生消费不敢肯定,但是这样的促销行为对一部分人一定会产生影响。 基于论坛数据的用户洞察在对论坛的研究方面,今年奥维咨询(AVC)提取了从2月份到3月份对某消费者论坛的监测数据,样本量是24万的用 户,其中签到的人达到了80万,购买信息数达到200万。对论坛用户年龄的分析,可以发现绝大部分都是85后和90后,这两部分用户占到70%以上,因此可以认定这是一个新型的消费领域。从学历方面来分析这些用户,80%以上的用户为专科以上学历,这些人渴望成功,渴望归属和友情,他们勇敢、时尚,但是消费能力不够。 在这个论坛用户结构中,普通人占到50%多,而骨灰级的粉丝占到40.3%,粉丝如何运营就是目前面临的最大问题。现在很多企业在做社会化的营销,在做粉丝运营,但是坦率来讲,做的都不是特别理想。目前家电行业都在向互联网思维转变,在产品和技术方面,企业并没有多大的问题,如果说企业还有哪些欠缺的话,应该就是思维上的转变、专业人才的培育与经验的积累。 在粉丝运营中,找准时间可以让营销事半功倍。之前所有电商网站购销行为,基本上都是在晚上11点到12点。但是论坛则不一样,如果企业有官网或者是官微,那么可以发现粉丝活跃时间是在午休时间,如果要做活动宣传、广告或者品牌推广,午休时间是个好选择。如果是做抢购、秒杀、团购、促销的活动,最好放在晚上。基于社会化用户的深度挖掘成为企业关注重点 如果只是基于在现有数据的条件下,进行深入挖掘以及用户分析,可能还远远不够,这时需要建立一个目标交互引流的分析模型,这个模型通过对线上用户精确的界定抓取,用于企业的用户运营、品牌分析。随着互联网和社会化的发展,企业需要对线上用户进行精确的分析和洞察。目前奥维咨询(AVC)在这方面已经形成了自己的产品模型特色,通过这样的模型可以有效实施这一类项目的操作和执行。 具体如何操作?首先要分析在互联网的行为下,用户对产品和品牌究竟有什么样的看法和观点,即满意度如何;还有产品是否迭代,原因是什么,企业的痛点又在哪里,有没有可能推送新的迭代创意或者是颠覆性的想法。通过这些方面,进行社会化的数据抓取,得到标准化的期望值,进行简单的画像,然后再进行分析,抽取相关的报表报告,提供给企业进行产品的设计和创意的输出。构建基于社会化大数据的用户洞察和交互体系 总结前面的分析,可以看出基于大数据的用户洞察和交互体系可以归纳为:基于营销为目的:分析用户的历史销售记录,基于用户群体,获取SNS的数据,处理清洗SNS数据,挖掘用户潜在需求,针对潜在客户进行精准的个性化、差异化营销和推荐,形成销售业绩。 基于洞察为目的:通过社会化媒体和电商平台找到关键的用户意见领袖和SNS用户,对他们细分得到相关的群体,通过社会化运营,可以对他进行调研,广告推送,或者搭建新一代用户调研系统,未来这将是能够解决产品跟进、快速升级的好平台。
1、数据挖掘的引入 面对山一样高的,海一样广的数据,我们该怎么办? 数据挖掘中的5W问题 为什么要使用数据挖掘? 数据挖掘是什么? 谁在使用数据挖掘? 数据挖掘有哪些方法? 数据挖掘使用在哪些领域? 百度百科中关于数据挖掘的定义如下: 数据挖掘(英语:Data mining),又译为资料探勘、数据采矿。它是数据库知识发现(英语:Knowledge-Discovery in Databases,简称:KDD)中的一个步骤。数据挖掘一般是指从大量的数据中通过算法搜索隐藏于其中信息的过程。数据挖掘是一门跨多个领域的交叉学科,通常与人工智能、模式识别及计算机科学有关,并通过统计、在线分析处理、情报检索、机器学习、专家系统(依靠过去的经验法则)和模式识别等诸多方法来实现上述目标。其特点为:海量数据寻知识、集成变换度量值、分析模式评效果、图形界面来展示。 数据挖掘主要构建四大类模型:分类、聚类、预测及关联。 分类 聚类 预测 关联 数据挖掘是BI领域的一个重要方向 BI通过对行业的认知、经验,结合数学理论、管理理论、市场营销理论,利用工具软件、数学算法(如:神经网路、遗传算法、聚类、客户细分等)对企业的数据、业务、市场进行分析及预测,以图表、数据分析报告的形式支撑企业决策、市场营销、业务拓展、信息运营等工作。 数据+人+工具+算法+知识+预测=商业智能(BI) 数据挖掘在电信行业的应用: 如何发现电信客户的特征和分类 如何预测哪些即将流失的客户 如何评价客户的贡献价值 如何判断客户的欺诈行为特征 如何发掘我的潜在客户 如何对欠费/坏账进行预测和控制 大客户的消费行为特征是什么,人口统计学特征是什么 如何知道公司未来一段时间收入情况,及某一收入因子对整个收入的影响指数 ……还有更多 2、数据挖掘建模方法 数据挖掘建模建模方法简介 数据挖掘过程模型独立于具体的数据挖掘模型和系统,从方法论的角度明确实施数据挖掘项目的流程和步骤。常用的有CRISP-DM,SEMMA和5A三种过程模型,如下图所示: 其中,SEMMA、5A及CRISP-DM过程模型如下各图示例 数据挖掘建模步骤1-商业理解 商业理解:理解商业目标和业务需求,幵转化为数据挖掘的问题定义。 常见的误区:很多人以为不需要事先确定问题和目标,只要对数据使用数据挖掘技术,然后再对分析挖掘后的结果进行寻找和解释,自然会找到一些以前我们不知道的,有用的规律和知识。 数据挖掘建模步骤2-数据理解 数据理解:筛选所需数据,校验数据质量,了解数据含义及特性。 数据理解,顾名思义就是基于对业务问题的梳理分析,找到合适的分析斱法戒者斱法论指导模型指标设计,确保指标体系化、全面性。 数据挖掘建模步骤3-数据准备(1) 数据挖掘建模步骤3-数据准备(2) 数据探索主要涉及两项工作:第一,进行数据检测、分析、验证是否符合指标设计初衷和业务涵义;第二,根据建模需要进行部分数据的标准化处理,使不同的指标在相同的量纲上进行数学运算。 数据挖掘建模步骤4-模型建立 根据建模场景进行算法选择:如描述类有分类规则、聚类分析,预测类有、神经网络、决策树、时间序列、回归分析、关联分析、贝叶斯网络、偏差检测,评估类有因子分析、主成分分析、数学公式;并结合数据情况(如离散值、连续值,数据量大小)等选择合适的算法 。 数据挖掘建模步骤5-模型评估 模型评估目的在于:什么样的模型是有效的?模型的实际应用效果如何? 根据样本数据,模型结果实际效果反馈数据迚行模型评估。 数据挖掘建模步骤6-模型发布 聚焦业务问题提供端到端的专题解决方案; 提高数据挖掘应用的效果和价值。 数据挖掘建模步骤7-模型优化 3、数据挖掘算法介绍 1)、聚类分析 2)、分类(决策树) 3)、预测(BP神经网路) BP神经网络是在现代神经生物学研究成果的基础上发展起来的一种模拟人脑信息处理机制的网络系统,它不但具有处理数值数据的一般计算能力,而且还具有处理知识的思维、学习、记忆能力。 在数据挖掘中经常利用神经网络的学习、记忆、模型工能进行一些预测。 基于神经网络的数据挖掘过程由数据准备、规则提取和规则应用、预测评估四个阶段组成。其中,规则提取是我们模型预测的核心。 4)、预测(回归) 5)、关联规则 6)、数据处理(主成分/因子分析) 7)、指纹算法 重入网识别技术-呼叫指纹算法 “呼叫指纹”,用户在使用电信运营商的产品及服务过程中所产生的交际圈、呼叫特征、短信特征、位置特征、客服特征、终端特征等信息。这些特征对每一用户而言,是相对稳定的,且存在个体差异。 重入网识别依据:利用“呼叫指纹”特征,建立新发展用户和老用户核心指纹库,指纹相似度越大,判断为统一用户的的概率越大。 4、数据挖掘应用案例 1)、流失预警模型 客户流失预警模型的建设目的是提前预测客户的流失可能性,根据客户特征对客户进行分群、建模,筛选出可能即将要流失的用户,辅助业务部门提高客户维系挽留工作的效率、提高维系成本的使用效率,降低客户流失率。 2)、用户真实性识别模型 根据用户入网以后的使用行为、使用位置、缴费特征等识别出虚假用户、欠真实性用户和真实性用户,从而根据不同的用户群采取不同的维系策略,如虚假用户的防范措施,欠真实性用户的补救措施 。 3)、客户细分模型
传统MySQL+ Memcached架构遇到的问题 实际MySQL是适合进行海量数据存储的,通过Memcached将热点数据加载到cache,加速访问,很多公司都曾经使用过这样的架构,但随着业务数据量的不断增加,和访问量的持续增长,我们遇到了很多问题: MySQL需要不断进行拆库拆表,Memcached也需不断跟着扩容,扩容和维护工作占据大量开发时间。 Memcached与MySQL数据库数据一致性问题。 Memcached数据命中率低或down机,大量访问直接穿透到DB,MySQL无法支撑。 跨机房cache同步问题。 众多NoSQL百花齐放,如何选择 最近几年,业界不断涌现出很多各种各样的NoSQL产品,那么如何才能正确地使用好这些产品,最大化地发挥其长处,是我们需要深入研究和思考的问题,实际归根结底最重要的是了解这些产品的定位,并且了解到每款产品的tradeoffs,在实际应用中做到扬长避短,总体上这些NoSQL主要用于解决以下几种问题 少量数据存储,高速读写访问。此类产品通过数据全部in-momery 的方式来保证高速访问,同时提供数据落地的功能,实际这正是Redis最主要的适用场景。 海量数据存储,分布式系统支持,数据一致性保证,方便的集群节点添加/删除。 这方面最具代表性的是dynamo和bigtable 2篇论文所阐述的思路。前者是一个完全无中心的设计,节点之间通过gossip方式传递集群信息,数据保证最终一致性,后者是一个中心化的方案设计,通过类似一个分布式锁服务来保证强一致性,数据写入先写内存和redo log,然后定期compat归并到磁盘上,将随机写优化为顺序写,提高写入性能。 Schema free,auto-sharding等。比如目前常见的一些文档数据库都是支持schema-free的,直接存储json格式数据,并且支持auto-sharding等功能,比如mongodb。 面对这些不同类型的NoSQL产品,我们需要根据我们的业务场景选择最合适的产品。Redis适用场景,如何正确的使用 前面已经分析过,Redis最适合所有数据in-momory的场景,虽然Redis也提供持久化功能,但实际更多的是一个disk-backed的功能,跟传统意义上的持久化有比较大的差别,那么可能大家就会有疑问,似乎Redis更像一个加强版的Memcached,那么何时使用Memcached,何时使用Redis呢? Redis与Memcached的比较 网络IO模型 Memcached是多线程,非阻塞IO复用的网络模型,分为监听主线程和worker子线程,监听线程监听网络连接,接受请求后,将连接描述字pipe 传递给worker线程,进行读写IO, 网络层使用libevent封装的事件库,多线程模型可以发挥多核作用,但是引入了cache coherency和锁的问题,比如,Memcached最常用的stats 命令,实际Memcached所有操作都要对这个全局变量加锁,进行计数等工作,带来了性能损耗。 (Memcached网络IO模型) Redis使用单线程的IO复用模型,自己封装了一个简单的AeEvent事件处理框架,主要实现了epoll、kqueue和select,对于单纯只有IO操作来说,单线程可以将速度优势发挥到最大,但是Redis也提供了一些简单的计算功能,比如排序、聚合等,对于这些操作,单线程模型实际会严重影响整体吞吐量,CPU计算过程中,整个IO调度都是被阻塞住的。 内存管理方面 Memcached使用预分配的内存池的方式,使用slab和大小不同的chunk来管理内存,Item根据大小选择合适的chunk存储,内存池的方式可以省去申请/释放内存的开销,并且能减小内存碎片产生,但这种方式也会带来一定程度上的空间浪费,并且在内存仍然有很大空间时,新的数据也可能会被剔除,原因可以参考Timyang的文章:http://timyang.net/data/Memcached-lru-evictions/ Redis使用现场申请内存的方式来存储数据,并且很少使用free-list等方式来优化内存分配,会在一定程度上存在内存碎片,Redis跟据存储命令参数,会把带过期时间的数据单独存放在一起,并把它们称为临时数据,非临时数据是永远不会被剔除的,即便物理内存不够,导致swap也不会剔除任何非临时数据(但会尝试剔除部分临时数据),这点上Redis更适合作为存储而不是cache。 数据一致性问题 Memcached提供了cas命令,可以保证多个并发访问操作同一份数据的一致性问题。 Redis没有提供cas 命令,并不能保证这点,不过Redis提供了事务的功能,可以保证一串 命令的原子性,中间不会被任何操作打断。 存储方式及其它方面 Memcached基本只支持简单的key-value存储,不支持枚举,不支持持久化和复制等功能 Redis除key/value之外,还支持list,set,sorted set,hash等众多数据结构,提供了KEYS 进行枚举操作,但不能在线上使用,如果需要枚举线上数据,Redis提供了工具可以直接扫描其dump文件,枚举出所有数据,Redis还同时提供了持久化和复制等功能。 关于不同语言的客户端支持 在不同语言的客户端方面,Memcached和Redis都有丰富的第三方客户端可供选择,不过因为Memcached发展的时间更久一些,目前看在客户端支持方面,Memcached的很多客户端更加成熟稳定,而Redis由于其协议本身就比Memcached复杂,加上作者不断增加新的功能等,对应第三方客户端跟进速度可能会赶不上,有时可能需要自己在第三方客户端基础上做些修改才能更好的使用。 根据以上比较不难看出,当我们不希望数据被踢出,或者需要除key/value之外的更多数据类型时,或者需要落地功能时,使用Redis比使用Memcached更合适。 关于Redis的一些周边功能 Redis除了作为存储之外还提供了一些其它方面的功能,比如聚合计算、pubsub、scripting等,对于此类功能需要了解其实现原理,清楚地了解到它的局限性后,才能正确的使用,比如pubsub功能,这个实际是没有任何持久化支持的,消费方连接闪断或重连之间过来的消息是会全部丢失的,又比如聚合计算和scripting等功能受Redis单线程模型所限,是不可能达到很高的吞吐量的,需要谨慎使用。 总的来说Redis作者是一位非常勤奋的开发者,可以经常看到作者在尝试着各种不同的新鲜想法和思路,针对这些方面的功能就要求我们需要深入了解后再使用。 总结: Redis使用最佳方式是全部数据in-memory。 Redis更多场景是作为Memcached的替代者来使用。 当需要除key/value之外的更多数据类型支持时,使用Redis更合适。 当存储的数据不能被剔除时,使用Redis更合适。 后续关于Redis文章计划: Redis数据类型与容量规划。 如何根据业务场景搭建稳定,可靠,可扩展的Redis集群。 Redis参数,代码优化及二次开发基础实践。 关于作者 田琪,目前负责新浪微博平台底层架构与研发工作,之前曾担任搜狐白社会实时游戏平台核心架构工作,主要关注webgame, 分布式存储,nosql 和 erlang 等领域,目前主要从事mysql源代码的一些深入研究工作,浪微博: http://weibo.com/bachmozart。 感谢张凯峰对本文的策划与审校。 给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家加入到InfoQ中文站用户讨论组中与我们的编辑和其他读者朋友交流。
RFM模型:R(Recency)表示客户最近一次购买的时间有多远,F(Frequency)表示客户在最近一段时间内购买的次数,M (Monetary)表示客户在最近一段时间内购买的金额。一般原始数据为3个字段:客户ID、购买时间、购买金额,用数据挖掘软件处理,加权(考虑权重)得到RFM得分,对得分排序,输出营销名单topN! RFM背后的逻辑很简单。近期下单的客户在不久的将来再次购买的概率可能性非常大。在过去有许多购买记录的顾客更有可能在不久的将来再次购买,并且在过去消费较多的客户更有可能在将来消费更多。RFM是一种最大化现有客户收益的技术,而不是吸引新客户的技术。 将客户分配大RFM单元中,三个RFM变量需要转化为三个量化指标。近期:距离上次购买的天数或周数,用于得到R的得分。第二个变量频率,通常是以前下单的总数,记录F的得分。最后一个是客户生存期中的总的花费,该值用于创建M的得分。每个维度5等分。由于维度之间具有相关性,如F维和M维,所以各个单元格的客户数量并不相等。要做的就是将所有的数据都分配到合适的单元格中,而且每个单元格要有足够多的记录,从而目标估计值具有一个可以接受的置信度。 3.1、RFM单元格转移 对于每个营销活动,客户都会在RFM单元格之间转移。那些做出响应的客户对增加其消费频率和消费总额,并且会减少距上一次购买的时间。这些新的取值通常都会迁移到单元格中。没有响应的客户也可能因距上一次购买时间的增加而转移到新的单元格。其实这就是定期的数据更新,模型更新。数据的迁移,会导致原来的期望的变化,在数据单元格迁移过程中,要不断的了解客户的需求,及时的更改数据。 3.2、RFM和增量响应建模 增量响应建模的目标是识别那些容易被说服的潜在客户——受营销影响最大的人。RFM可以看成是对客户营销活动响应能力的预测。在定义好的RFM单元格之后,需要为每个单元格分配成员,要么是接收营销信息的测试组成员,要么就是不接受该信息的对照组成员。基于测试组和对照组两个分组之间的响应率之差决定了营销活动对于发现潜在客户的能力。对于测试组和对照组之间的响应率差异最大的单元格,营销获得产生的影响也是最大的。但这些单元格的响应率却未必是最大的。 三十多年来,直邮营销的市场商人使用非正式RFM分析为非盈利性组织把邮件发给最有可能捐赠的客户。RFM背后的道理很简单:曾经捐赠过的人更有可能再度捐赠。随着电子邮件行销活动和客户关系管理软件的出现, RFM评估已成为一个重要的工具。使用RFM分析,客户按照每个RFM参数可以被分成1,2,3,4,5(5是最高级别)五个级别。这三个分数一起被称为RFM单元(cell)。按照数据库的分类来确定哪些客户过去是“最好的客户”,如果一个单元排序为“ 555 ” 那自然是最理想的。 虽然RFM分析是一种有用的工具,但它也有局限性。公司必须小心,不要过度恳求有最高等级的客户。专家们也告诫商家要记住,不应忽视低单元等级的客户,相反应该培养其成为更好的客户。
分布式缓存架构 先看架构: 图一 用户通过访问http服务器,然后访问应用服务器资源,应用服务器调用后端的数据库,在第一次访问的时候,直接访问数据库,然后将要缓存的内容放入memcached集群,集群规模根据缓存文件的大小而定。在第二次访问的时候就直接进入缓存读取,不需要进行数据库的操作。这个适合数据变化不频繁的场景,比如:互联网站显示的榜单、阅读排行等。 博客园的48小时阅读排行就类似于这一种: 当然,缓存的架构使用方式不止这一种方式,在数据挖掘系统中,对于不频繁更新的数据或者离线的数据都可以使用这种方式。具体的应用需要在不同的场景下进行架构设计。 一致性hash 一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似。一致性哈希修正了CARP使用的简 单哈希算法带来的问题,使得分布式哈希(DHT)可以在P2P环境中真正得到应用。 一致性hash算法提出了在动态变化的Cache环境中,判定哈希算法好坏的四个定义: 1、平衡性(Balance):平衡性是指哈希的结果能够尽可能分布到所有的缓冲中去,这样可以使得所有的缓冲空间都得到利用。很多哈希算法都能够满足这一条件。 2、单调性(Monotonicity):单调性是指如果已经有一些内容通过哈希分派到了相应的缓冲中,又有新的缓冲加入到系统中。哈希的结果应能够保证原有已分配的内容可以被映射到原有的或者新的缓冲中去,而不会被映射到旧的缓冲集合中的其他缓冲区。 3、分散性(Spread):在分布式环境中,终端有可能看不到所有的缓冲,而是只能看到其中的一部分。当终端希望通过哈希过程将内容映射到缓冲上时,由于不同终端所见的缓冲范围有可能不同,从而导致哈希的结果不一致,最终的结果是相同的内容被不同的终端映射到不同的缓冲区中。这种情况显然是应该避免的,因为它导致相同内容被存储到不同缓冲中去,降低了系统存储的效率。分散性的定义就是上述情况发生的严重程度。好的哈希算法应能够尽量避免不一致的情况发生,也就是尽量降低分散性。 4、负载(Load):负载问题实际上是从另一个角度看待分散性问题。既然不同的终端可能将相同的内容映射到不同的缓冲区中,那么对于一个特定的缓冲区而言,也可能被不同的用户映射为不同 的内容。与分散性一样,这种情况也是应当避免的,因此好的哈希算法应能够尽量降低缓冲的负荷。 在分布式集群中,对机器的添加删除,或者机器故障后自动脱离集群这些操作是分布式集群管理最基本的功能。如果采用常用的hash(object)%N算法,那么在有机器添加或者删除后,很多原有的数据就无法找到了,这样严重的违反了单调性原则。接下来主要讲解一下一致性哈希算法是如何设计的: 1、 hash机器节点 首先求出机器节点的hash值(怎么算机器节点的hash?ip可以作为hash的参数吧。。当然还有其他的方法了),然后将其分布到0~2^32的一个圆环上(顺时针分布)。如下图所示: 图二 集群中有机器:A , B, C, D, E五台机器,通过一定的hash算法我们将其分布到如上图所示的环上。 2、访问方式 如果有一个写入缓存的请求,其中Key值为K,计算器hash值Hash(K), Hash(K) 对应于图 – 1环中的某一个点,如果该点对应没有映射到具体的某一个机器节点,那么顺时针查找,直到第一次找到有映射机器的节点,该节点就是确定的目标节点,如果超过了2^32仍然找不到节点,则命中第一个机器节点。比如 Hash(K) 的值介于A~B之间,那么命中的机器节点应该是B节点(如上图 )。 3、增加节点的处理 如上图二,在原有集群的基础上欲增加一台机器F,增加过程如下: 计算机器节点的Hash值,将机器映射到环中的一个节点,如下图: 图三 增加机器节点F之后,访问策略不改变,依然按照(2)中的方式访问,此时缓存命不中的情况依然不可避免,不能命中的数据是hash(K)在增加节点以前落在C~F之间的数据。尽管依然存在节点增加带来的命中问题,但是比较传统的 hash取模的方式,一致性hash已经将不命中的数据降到了最低。 Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。Memcached基于一个存储键/值对的hashmap。其守护进程(daemon )是用C写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信。下图图四介绍的是缓存的拓补结构: 图四 Memcached的特点包括: 全内存运转 哈希方式存储 简单文本协议进行数据通信 叧操作字符型数据 其它类型数据由应用解释,序列化以及反序列化 集群也由应用进行控制,采用一致性散列(哈希)算法 Memcached变种产品介绍 国内外有很多基于Memcached开发的产品,这些产品支持所有Memcached的协议,同时侧重不同的应用场景,可以根据自己的应用需求选择合适的Memcached变种。下面分别介绍几种Memcached的变种产品。 1. memcachedb memcachedb是新浪网基于Memcached开发的一个开源项目。通过为Memcached增加Berkeley DB的持久化存储机制和异步主辅复制机制,使Memcached具备了事务恢复能力、持久化能力和分布式复制能力,非常适合需要超高性能读写速度、持久化保存的应用场景,例如,将memcachedb应用于新浪博客的管理。如果对Memcached有持久化需求,可以考虑使用memcachedb。 2. repcached repcached是日本人开发的基于Memcached的一个patch,实现Memcached的复制功能,它支持多个Memcached之间相互复制,可以解决Memcached的容灾问题。有cache容灾需求的可以尝试使用这一功能。 3. memcached_functions_mysql 这个功能相当于MySQL的UDFs(User Defined Functions),在MySQL中通过触发器更新Memcached。这样可以做到把数据写入MySQL,然后从Memcached获取数据,以减轻数据库的压力,同时减少很多开发的工作量。 关于memcached_functions_mysql的使用和经验会在下一节进行详细介绍。 4. memcacheQ memcacheQ在Memcached的基础上实现了消息队列。下面以PHP客户端为例介绍memcacheQ实现消息队列的方式。 消息从尾部入栈:memcache_set 消息从头部出栈:memcache_get memcacheQ最大的优势是:它是基于Memcached开发的,可以通过各种Memcached命令对它进行操作。基于Memcached开发的应用完全不需要做任何修改。 总结 分布式缓存通常用在频繁访问或者不能实时处理的情况下,使用场景包括: 1、访问量大于更新量的场景。 2、需要离线处理数据的场景。 3、后端为列式数据库的场景。 还有其它很多的应用场景与数据挖掘系统的模型层进行整合,快速提供访问模型处理结果,总之,在架构设计中很好的利用缓存将极大的提高应用程序的性能,使整个系统更加健壮。
我发现很多人的服务器上都运行着一些诸如每天切分Nginx日志之类的CRON脚本,大家似乎遗忘了Logrotate,争相发明自己的轮子,这真是让人沮丧啊!就好比明明身边躺着现成的性感美女,大家却忙着自娱自乐,罪过! Logrotate的介绍 显而易见,Logrotate是基于CRON来运行的,其脚本是「/etc/cron.daily/logrotate」: #!/bin/sh /usr/sbin/logrotate /etc/logrotate.conf EXITVALUE=$? if [ $EXITVALUE != 0 ]; then /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]" fi exit 0 实际运行时,Logrotate会调用配置文件「/etc/logrotate.conf」: # see "man logrotate" for details # rotate log files weekly weekly # keep 4 weeks worth of backlogs rotate 4 # create new (empty) log files after rotating old ones create # uncomment this if you want your log files compressed #compress # RPM packages drop log rotation information into this directory include /etc/logrotate.d # no packages own wtmp -- we'll rotate them here /var/log/wtmp { monthly minsize 1M create 0664 root utmp rotate 1 } # system-specific logs may be also be configured here. 这里的设置可以理解为Logrotate的缺省值,当然了,可以我们在「/etc/logrotate.d」目录里放置自己的配置文件,用来覆盖Logrotate的缺省值。 Logrotate的演示 按天保存一周的Nginx日志压缩文件,配置文件为「/etc/logrotate.d/nginx」: /usr/local/nginx/logs/*.log { daily dateext compress rotate 7 sharedscripts postrotate kill -USR1 `cat /var/run/nginx.pid` endscript } 如果你等不及CRON,可以通过如下命令来手动执行: shell> logrotate -f /etc/logrotate.d/nginx 当然,正式执行前最好通过Debug选项来验证一下,这对调试也很重要: shell> logrotate -d -f /etc/logrotate.d/nginx BTW:类似的还有Verbose选项,这里就不多说了。 Logrotate的疑问 问题:sharedscripts的作用是什么? 大家可能注意到了,我在前面Nginx的例子里声明日志文件的时候用了星号通配符,也就是说这里可能涉及多个日志文件,比如:access.log和error.log。说到这里大家或许就明白了,sharedscripts的作用是在所有的日志文件都轮转完毕后统一执行一次脚本。如果没有配置这条指令,那么每个日志文件轮转完毕后都会执行一次脚本。 问题:rotate和maxage的区别是什么? 它们都是用来控制保存多少日志文件的,区别在于rotate是以个数为单位的,而maxage是以天数为单位的。如果我们是以按天来轮转日志,那么二者的差别就不大了。 问题:为什么生成日志的时间是凌晨四五点? 前面我们说过,Logrotate是基于CRON运行的,所以这个时间是由CRON控制的,具体可以查询CRON的配置文件「/etc/crontab」,可以手动改成如23:59等时间执行: SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root HOME=/ # run-parts 01 * * * * root run-parts /etc/cron.hourly 59 23 * * * root run-parts /etc/cron.daily 22 4 * * 0 root run-parts /etc/cron.weekly 42 4 1 * * root run-parts /etc/cron.monthly 如果使用的是新版CentOS,那么配置文件为:/etc/anacrontab。 问题:如何告诉应用程序重新打开日志文件? 以Nginx为例,是通过postrotate指令发送USR1信号来通知Nginx重新打开日志文件的。但是其他的应用程序不一定遵循这样的约定,比如说MySQL是通过flush-logs来重新打开日志文件的。更有甚者,有些应用程序就压根没有提供类似的方法,此时如果想重新打开日志文件,就必须重启服务,但为了高可用性,这往往不能接受。还好Logrotate提供了一个名为copytruncate的指令,此方法采用的是先拷贝再清空的方式,整个过程中日志文件的操作句柄没有发生改变,所以不需要通知应用程序重新打开日志文件,但是需要注意的是,在拷贝和清空之间有一个时间差,所以可能会丢失部分日志数据。 BTW:MySQL本身在support-files目录已经包含了一个名为mysql-log-rotate的脚本,不过它比较简单,更详细的日志轮转详见「Rotating MySQL Slow Logs Safely」。 … 熟悉Apache的朋友可能会记得cronolog,不过Nginx并不支持它,有人通过mkfifo命令曲线救国,先给日志文件创建管道,再搭配cronolog轮转,虽然理论上没有问题,但效率上有折扣。另外,Debian/Ubuntu下有一个简化版工具savelog,有兴趣可以看看。
Nagios简介 Nagios是十分受欢迎的、开源且免费的计算机及网络系统监控软件。Nagios是“Nagios Ain‘t Gonna Insist On Sainthood”的缩写。它最早是在1999年以“NetSaint”发布。Nagios主要应用在Linux和Unix平台环境下的监控,但通过插件,也可以监控MS Windows系统的主机。Nagios在LinuxCon 2010 Poll并选为最受欢迎的IT运维工具。它被Infoworld在2009年评为最佳开源软件,同时也是该年度的SourceForge社区的系统管理工具最佳选择。Nagios也被很多知名企业所采用,包括AOL,DHL,At&t,欧莱雅,德州仪器,Siemens COM CZ,时代华纳有线,Yahoo等。 Nagios的特征包括: l 监控网络服务(SMTP、POP3、HTTP、NNTP、PING等); l 监控主机资源(处理器负荷、磁盘利用率等); l 并行服务检查机制; l 具备定义网络分层结构的能力,用”parent”主机定义来表达网络主机间的关系,这种关系可被用来发现和明晰主机宕机或不可达状态,提供设备组网拓扑展示能力; l 当服务或主机问题产生与解决时将告警发送给联系人(通过EMail、短信、用户定义方式); l 具备定义事件句柄功能,它可以在主机或服务的事件发生时获取更多问题定位; l 简单地插件设计使得用户可以方便地扩展自己服务的检测方法; l 自动的日志轮转; l 可以支持并实现对主机的冗余监控; l 可选的WEB界面用于查看当前的网络状态、通知和故障历史、日志文件等; 二次开发 Nagios的功能是监控服务和主机,但是他自身并不包括这部分功能,所有的监控、检测功能都是通过各种插件来完成的。启动 Nagios后,它会周期性的自动调用插件去检测服务器状态,同时 Nagios 会维持一个队列,所有插件返回来的状态信息都进入队列,Nagios每次都从队首开始读取信息,并进行处理后,把状态结果通过 web 显示出来。 Nagios Plug-in机制 Nagios Daemon通过加载一些官方的或其它自开发的插件(Plug-in),能够实现对诸如服务器、网络、应用甚至房间温度和湿度等的监控。Nagios Core作为Nagios Daemon的核心,负责对这些插件的结果进行处理(诸如统计、转储、人工或自动响应处理等)。因此Nagios Core即为Nagios的事件池的核心。在Nagios Core内部,它为每一种加载的插件都会分配独立的工作缓冲区(即以objecttype作为区分),以存放相应插件所产生的事件信息。每一个独立运行的Nagios Daemon可以有自己的名称以便集群Nagios环境下的相互区别,即从更大的层面来区分这些工作缓冲区。 Nagios插件通常是通过命令行方式监控主机或服务工作状态的脚本,由Nagios进行按需调用,并把执行结果返回给Nagios。Nagios正是根据这些返回值来判断是否“采取某种行动”(如运行事件句柄(event handlers),发送通知等)。下图展示了插件相对于Nagios进程和被监控对象间的关系: 为了管理插件,Nagios 每次在查询一个服务的状态时,产生一个子进程,并且它使用来自该命令的输出和退出代码来确定具体的状态。 下面提供了一个 Python 示例脚本,用于检查 UNIX® 平均负载。它假定 2.0 以上的级别表示警告状态,而 5.0 以上的级别表示危险状态。这些值都采用了硬编码的方式,并且始终使用最近一分钟的平均负载。 Nagios Add-on机制 Nagios支持以Add-on方式扩展监控信息处理能力。Nagios采集到的监控信息都被看做事件,事件接收者对感兴趣的事件注册,事件发生时Nagios的事件机制会将事件发送到事件接收者。Nagios的Add-on就是事件接收者。Add-on通过将自身注册到感兴趣的事件上,可以实时的从Nagios接收到事件,并作出相应处理。 Nagios Add-on工作原理图: Nagios监控效果:
导读:数据可视化,是一种用来将复杂信息数据清晰表述出来的强大有力的工具。通过可视化信息,我们的大脑可以更有效地合成和保留信息内容,增强对信息的理解。但是如果不正确数据可视化,它可能弊大于利。错误的图表可以减少数据的信息,或者更糟的是,完全背道而驰!这就是完美的数据可视化极其依赖设计的原因。 设计师要做的,不仅仅是选择合适的图表类型,更要以一种容易理解的方式来呈现信息,设计出更直观的导航系统,让观众做尽可能减少理解方面的麻烦,做到一目了然。 当然,并不是所有的设计师是数据可视化专家,这就是为什么大部分的图表看上去是那么滴糟糕,简直就是一坨屎! 这里有10个数据可视化的案例,包括你可能犯的错误和快速修复补救的方法。 错误1.混乱的饼图分割 饼图,是最简单的图表之一。不过偏偏有人喜欢把它搞得很复杂。 饼图的设计应该直观而清晰,理论上,一个饼图不应该分割超过5块。下面就是两种可以让读者的注意力瞬间集中到你要表述的重点的方法。 第一种:将最大的部分放在12点钟方位,要顺时针。第二部分12点钟,逆时针方向。剩下的部分可以放在下面,继续逆时针方向。 方法二:最大一块12点钟开始,顺时针方向旋转。剩余部分在降序排列,顺时针。 错误2.在折线图中使用不连贯的线条 虚线,虚线容易分散注意力。相反,使用实线和颜色,反而容易区分彼此的区别。 错误3.数据排序混乱 你的内容应该以一种合乎逻辑的和直观的方式来引导读者了解数据。所以,记得将数据类别按字母顺序,大小顺序,或价值进行排序。 错误4.数据模糊不清 确保没有数据丢失或被设计。例如,使用标准的面积图时,可以添加透明度,确保读者可以看到所有数据。 错误5.让读者自己解读 设计师应该使图表尽可能轻松地帮助读者理解数据。例如,在散点图中添加趋势线来强调的趋势。 错误6.扭曲数据 确保所有可视化方式是准确的。例如,气泡图大小应该根据区域扩展,而不是直径。 错误7.在一张热力图上使用不同的颜色 颜色用得太花,会给数据增加不可承受之重,相反,设计师应该采用同一色系,或者类比色。 错误8.条状图太胖或太瘦 或许你的报告很有创意,非常精彩,但是记得图表设计水平也要跟上。条形图之间的间隔应该是1/2栏宽度. 错误9.很难比较数据 比较是展示数据差异的好法子,但是如果你的读者不容易看出差别的话,那么你的比较就毫无意义。确保所有的数据都是呈现在读者面前,选择最合适的比较方法。 错误10:用3D图表 虽然他们看起来很酷,但是3d形状可以扭曲感知,因此扭曲数据。坚持2 次元,确保数据准确。 怎么样,上述10条,你中枪了没有?
随着Hadoop版本的演化,Fair Scheduler和Capacity Scheduler的功能越来越完善,包括层级队列组织方式、资源抢占、批量调度等,也正因如此,两个调度器同质化越来越严重,目前看了,两个调度器从设计到支持的特性等方面非常接近,而由于Fair Scheduler支持多种调度策略,现在看来,可以认为Fair Scheduler具备了Capacity Scheduler具有的所有功能。 下表从多个方面对比了Hadoop 2.0(YARN)中这两个调度器的异同,通过这个表读者能更好地理解Capacity Scheduler与Fair Scheduler的相同点和不同点。 其中,FIFO、FAIR和DRF分别是指先来先服务、公平调度和主资源公平调度,具体含义如下: FIFO:先按照优先级高低调度,如果优先级相同,则按照提交时间先后顺序调度,如果提交时间相同,则按照(队列或者应用程序)名称大小(字符串比较)调度; FAIR:按照内存资源使用量比率调度,即按照used_memory/minShare大小调度(核心思想是按照该调度算法决定调度顺序,但还需考虑一些边界情况); DRF:借鉴了Mesos中的设计策略,按照主资源公平调度算法进行调度,具体已经在Apache Mesos调度器机制进行了介绍。 【总结】在MRv1和YARN中,尽管Fair Scheduler和Capacity Scheduler均是插拔式的,且实现原理基本一致,但由于YARN采用了事件驱动的编程模型,因此,它的资源调度器设计更加复杂,它要求用户不仅要了解基本的编程接口,还要理解ResourceManager与资源调度器之间基于事件的交互逻辑。 原创文章,转载请注明: 转载自董的博客 本文链接地址: http://dongxicheng.org/mapreduce-nextgen/hadoop-2-0-capacity-scheduler-fair-scheduler/
什么是数据挖掘 前两天看到群里有人问,什么是数据挖掘,现在就数据挖掘的概念做一下分析,并且尽量用大白话说一下数据挖掘到底是个啥东西,为啥大数据来了数据挖掘也火了(其实原来就挺火)。 先看一上概念: 数据挖掘(英语:Data mining),又译为资料探勘、数据采矿。它是数据库知识发现(英语:Knowledge-Discovery in Databases,简称:KDD)中的一个步骤。数据挖掘一般是指从大量的数据中通过算法搜索隐藏于其中信息的过程。数据挖掘通常与计算机科学有关,并通过统计、在线分析处理、情报检索、机器学习、专家系统(依靠过去的经验法则)和模式识别等诸多方法来实现上述目标。 数据挖掘简介 数据挖掘说的直白些就是在海量的数据中找到有价值的数据,为企业经营决策提供依据。 价值包括以下几类: 1、相关性 相关性分析是指对两个或多个具备相关性的变量元素进行分析,从而衡量两个变量因素的相关密切程度。相关性的元素之间需要存在一定的联系或者概率才可以进行相关性分析。相关性不等于因果性,也不是简单的个性化,相关性所涵盖的范围和领域几乎覆盖了我们所见到的方方面面,相关性在不同的学科里面的定义也有很大的差异。用于确定数据之间的变化情况,即其中一个属性或几个属性变化的是否会对其它属性造成影响,影响有多大。 下图就是相关性的示例: 2、趋势 是指将实际达到的结果,与不同时期财务报表中同类指标的历史数据进行比较 ,从而确定财务状况,经营成果和现金流量的变化趋势和变化规律的一种分析方法。可以通过拆线图预测数据的走向和趋势,也可以通过环比、同比的方式对比较的结果进行说明。 如下图所示: 3、特征 看具体分析的内容是什么,比如互联网类,就是用户画像这类的需求,根据不同的用户给用户群打相应的标签。 下图是一个示意图: 展现形式 数据挖掘的结果一般有几种展现形式: 1、表格 最早的一种展现方式,交叉表的展示,如下图: 2、图表 相比于图表更具展现力,让人很直观的就能看出数据的整体情况,如下图: 3、决策树 套用俗语,决策树分类的思想类似于找对象。现想象一个女孩的母亲要给这个女孩介绍男朋友,于是有了下面的对话: 女儿:多大年纪了? 母亲:26。 女儿:长的帅不帅? 母亲:挺帅的。 女儿:收入高不? 母亲:不算很高,中等情况。 女儿:是公务员不? 母亲:是,在税务局上班呢。 女儿:那好,我去见见。 这个女孩的决策过程就是典型的分类树决策。相当于通过年龄、长相、收入和是否公务员对将男人分为两个类别:见和不见。假设这个女孩对男人的要求是:30岁以下、长相中等以上并且是高收入者或中等以上收入的公务员,那么这个可以用下图表示女孩的决策逻辑: 数据挖掘涉及的领域 数据挖掘是计算机学科中的一个交叉研究领域,其研究方法与多个其他科学紧密相连,如:统计、机2器学习、专家系统、信息检索、社会网络、自然语言处理和模式识别等等。 总结 这里简单的介绍了一下数据挖掘的概念以及数据挖掘的展现形式和数据挖掘到底能做一些什么,在后面会继续深和的介绍,以期和大家一起提高。
一个网页设计师在设计网站的各个关键方面时,他们需要了解网站的各种必要细节,可通过市场调研或者是网站本身的统计来获取这些细节信息。 本文介绍的这些工具确实可以帮助网站进行适当和有效的分析。这里面有些是免费的工具,还有的提供非常强大的搜索功能,以及网站的评级。 下面是详细的列表: 1) Piwik Piwik是一套基于Php+MySQL技术构建的开源网站访问统计系统,前身是phpMyVisites。Piwik可以给你详细的统计信息,比如网页 浏览人数, 访问最多的页面, 搜索引擎关键词等等,并且采用了大量的AJAX/Flash技术,使得在操作上更加便易。此外,它还采用了插件扩展及开放API架构,可以让开发人员根据 自已的实际需求创建更多的功能. 2) Crazyegg Crazyegg 是一个网站访问热图,可方便的了解用户在网站上的行为,提供了用户点击热点的可视化呈现。 3) Compete Compete 的流量和参与指标可显示你和你的竞争对手的比较,以及如何吸引和留住客户。了解哪些网站和渠道是其最富有成效的,并依此来指定更有效的反向流量收购战略,并微调自己的营销策略。 4) Optimizely 简单、快速、强大。Optimizely 使用 A/B 测试来改善网站,无需编码要求,只需简单点击和复制粘贴操作。 5) Get Clicky 你网站上的流量数据是非常宝贵的资源,问题是如何快速、即时的访问这些数据,而 Clicky 提供了日志的统计汇总功能,强大而且直观。 6) w3counter 你也可以不安装自己的统计软件,使用 W3Counter 是一个免费的、托管的、易用的网站分析解决方案,你可以通过它了解你的访客以及他们是从哪来的,他们对什么感兴趣。 7) w3perl W3Perl 是一个Web日志的分析工具,支持 FTP、Squid、邮件日志等,提供一个图形化的界面,以及文本统计数据,提供一个管理界面。 8 ) Alexa 9) Google Analytics 10) Tracewatch TraceWatch 实时网站统计和流量分析可让你通过直观的接口实时跟踪网站上访客。
目录 一、优化概述 二、查询与索引优化分析 1性能瓶颈定位 Show命令 慢查询日志 explain分析查询 profiling分析查询 2索引及查询优化 三、配置优化 1) max_connections 2) back_log 3) interactive_timeout 4) key_buffer_size 5) query_cache_size 6) record_buffer_size 7) read_rnd_buffer_size 8) sort_buffer_size 9) join_buffer_size 10) table_cache 11) max_heap_table_size 12) tmp_table_size 13) thread_cache_size 14) thread_concurrency 15) wait_timeout 一、 优化概述 MySQL数据库是常见的两个瓶颈是CPU和I/O的瓶颈,CPU在饱和的时候一般发生在数据装入内存或从磁盘上读取数据时候。磁盘I/O瓶颈发生在装入数据远大于内存容量的时候,如果应用分布在网络上,那么查询量相当大的时候那么平瓶颈就会出现在网络上,我们可以用mpstat, iostat, sar和vmstat来查看系统的性能状态。 除了服务器硬件的性能瓶颈,对于MySQL系统本身,我们可以使用工具来优化数据库的性能,通常有三种:使用索引,使用EXPLAIN分析查询以及调整MySQL的内部配置。 二、查询与索引优化分析 在优化MySQL时,通常需要对数据库进行分析,常见的分析手段有慢查询日志,EXPLAIN 分析查询,profiling分析以及show命令查询系统状态及系统变量,通过定位分析性能的瓶颈,才能更好的优化数据库系统的性能。 1 性能瓶颈定位Show命令 我们可以通过show命令查看MySQL状态及变量,找到系统的瓶颈: Mysql> show status ——显示状态信息(扩展show status like ‘XXX’) Mysql> show variables ——显示系统变量(扩展show variables like ‘XXX’) Mysql> show innodb status ——显示InnoDB存储引擎的状态 Mysql> show processlist ——查看当前SQL执行,包括执行状态、是否锁表等 Shell> mysqladmin variables -u username -p password——显示系统变量 Shell> mysqladmin extended-status -u username -p password——显示状态信息 查看状态变量及帮助: Shell> mysqld –verbose –help [|more #逐行显示] 比较全的Show命令的使用可参考: http://blog.phpbean.com/a.cn/18/ 慢查询日志 慢查询日志开启: 在配置文件my.cnf或my.ini中在[mysqld]一行下面加入两个配置参数 log-slow-queries=/data/mysqldata/slow-query.log long_query_time=2 注:log-slow-queries参数为慢查询日志存放的位置,一般这个目录要有mysql的运行帐号的可写权限,一般都将这个目录设置为mysql的数据存放目录; long_query_time=2中的2表示查询超过两秒才记录; 在my.cnf或者my.ini中添加log-queries-not-using-indexes参数,表示记录下没有使用索引的查询。 log-slow-queries=/data/mysqldata/slow-query.log long_query_time=10 log-queries-not-using-indexes 慢查询日志开启方法二: 我们可以通过命令行设置变量来即时启动慢日志查询。由下图可知慢日志没有打开,slow_launch_time=# 表示如果建立线程花费了比这个值更长的时间,slow_launch_threads 计数器将增加 设置慢日志开启 MySQL后可以查询long_query_time 的值 。 为了方便测试,可以将修改慢查询时间为5秒。 慢查询分析mysqldumpslow 我们可以通过打开log文件查看得知哪些SQL执行效率低下 [root@localhost mysql]# more slow-query.log # Time: 081026 19:46:34 # User@Host: root[root] @ localhost [] # Query_time: 11 Lock_time: 0 Rows_sent: 1 Rows_examined: 6552961 select count(*) from t_user; 从日志中,可以发现查询时间超过5 秒的SQL,而小于5秒的没有出现在此日志中。 如果慢查询日志中记录内容很多,可以使用mysqldumpslow工具(MySQL客户端安装自带)来对慢查询日志进行分类汇总。mysqldumpslow对日志文件进行了分类汇总,显示汇总后摘要结果。 进入log的存放目录,运行 [root@mysql_data]#mysqldumpslow slow-query.log Reading mysql slow query log from slow-query.log Count: 2 Time=11.00s (22s) Lock=0.00s (0s) Rows=1.0 (2), root[root]@mysql select count(N) from t_user; mysqldumpslow命令 /path/mysqldumpslow -s c -t 10 /database/mysql/slow-query.log 这会输出记录次数最多的10条SQL语句,其中: -s, 是表示按照何种方式排序,c、t、l、r分别是按照记录次数、时间、查询时间、返回的记录数来排序,ac、at、al、ar,表示相应的倒叙; -t, 是top n的意思,即为返回前面多少条的数据; -g, 后边可以写一个正则匹配模式,大小写不敏感的; 例如: /path/mysqldumpslow -s r -t 10 /database/mysql/slow-log 得到返回记录集最多的10个查询。 /path/mysqldumpslow -s t -t 10 -g “left join” /database/mysql/slow-log 得到按照时间排序的前10条里面含有左连接的查询语句。 使用mysqldumpslow命令可以非常明确的得到各种我们需要的查询语句,对MySQL查询语句的监控、分析、优化是MySQL优化非常重要的一步。开启慢查询日志后,由于日志记录操作,在一定程度上会占用CPU资源影响mysql的性能,但是可以阶段性开启来定位性能瓶颈。 explain分析查询 使用 EXPLAIN 关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的。这可以帮你分析你的查询语句或是表结构的性能瓶颈。通过explain命令可以得到: – 表的读取顺序 – 数据读取操作的操作类型 – 哪些索引可以使用 – 哪些索引被实际使用 – 表之间的引用 – 每张表有多少行被优化器查询 EXPLAIN字段: ØTable:显示这一行的数据是关于哪张表的 Øpossible_keys:显示可能应用在这张表中的索引。如果为空,没有可能的索引。可以为相关的域从WHERE语句中选择一个合适的语句 Økey:实际使用的索引。如果为NULL,则没有使用索引。MYSQL很少会选择优化不足的索引,此时可以在SELECT语句中使用USE INDEX(index)来强制使用一个索引或者用IGNORE INDEX(index)来强制忽略索引 Økey_len:使用的索引的长度。在不损失精确性的情况下,长度越短越好 Øref:显示索引的哪一列被使用了,如果可能的话,是一个常数 Ørows:MySQL认为必须检索的用来返回请求数据的行数 Øtype:这是最重要的字段之一,显示查询使用了何种类型。从最好到最差的连接类型为system、const、eq_reg、ref、range、index和ALL nsystem、const:可以将查询的变量转为常量. 如id=1; id为 主键或唯一键. neq_ref:访问索引,返回某单一行的数据.(通常在联接时出现,查询使用的索引为主键或惟一键) nref:访问索引,返回某个值的数据.(可以返回多行) 通常使用=时发生 nrange:这个连接类型使用索引返回一个范围中的行,比如使用>或<查找东西,并且该字段上建有索引时发生的情况(注:不一定好于index) nindex:以索引的顺序进行全表扫描,优点是不用排序,缺点是还要全表扫描 nALL:全表扫描,应该尽量避免 ØExtra:关于MYSQL如何解析查询的额外信息,主要有以下几种 nusing index:只用到索引,可以避免访问表. nusing where:使用到where来过虑数据. 不是所有的where clause都要显示using where. 如以=方式访问索引. nusing tmporary:用到临时表 nusing filesort:用到额外的排序. (当使用order by v1,而没用到索引时,就会使用额外的排序) nrange checked for eache record(index map:N):没有好的索引. profiling分析查询 通过慢日志查询可以知道哪些SQL语句执行效率低下,通过explain我们可以得知SQL语句的具体执行情况,索引使用等,还可以结合show命令查看执行状态。 如果觉得explain的信息不够详细,可以同通过profiling命令得到更准确的SQL执行消耗系统资源的信息。 profiling默认是关闭的。可以通过以下语句查看 打开功能: mysql>set profiling=1; 执行需要测试的sql 语句: mysql> show profiles\G; 可以得到被执行的SQL语句的时间和ID mysql>show profile for query 1; 得到对应SQL语句执行的详细信息 Show Profile命令格式: SHOW PROFILE [type [, type] … ] [FOR QUERY n] [LIMIT row_count [OFFSET offset]] type: ALL | BLOCK IO | CONTEXT SWITCHES | CPU | IPC | MEMORY | PAGE FAULTS | SOURCE | SWAPS 以上的16rows是针对非常简单的select语句的资源信息,对于较复杂的SQL语句,会有更多的行和字段,比如converting HEAP to MyISAM 、Copying to tmp table等等,由于以上的SQL语句不存在复杂的表操作,所以未显示这些字段。通过profiling资源耗费信息,我们可以采取针对性的优化措施。 测试完毕以后 ,关闭参数:mysql> set profiling=0 2 索引及查询优化 索引的类型 Ø 普通索引:这是最基本的索引类型,没唯一性之类的限制。 Ø 唯一性索引:和普通索引基本相同,但所有的索引列值保持唯一性。 Ø 主键:主键是一种唯一索引,但必须指定为”PRIMARY KEY”。 Ø 全文索引:MYSQL从3.23.23开始支持全文索引和全文检索。在MYSQL中,全文索引的索引类型为FULLTEXT。全文索引可以在VARCHAR或者TEXT类型的列上创建。 大多数MySQL索引(PRIMARY KEY、UNIQUE、INDEX和FULLTEXT)使用B树中存储。空间列类型的索引使用R-树,MEMORY表支持hash索引。 单列索引和多列索引(复合索引) 索引可以是单列索引,也可以是多列索引。对相关的列使用索引是提高SELECT操作性能的最佳途径之一。 多列索引: MySQL可以为多个列创建索引。一个索引可以包括15个列。对于某些列类型,可以索引列的左前缀,列的顺序非常重要。 多列索引可以视为包含通过连接索引列的值而创建的值的排序的数组。一般来说,即使是限制最严格的单列索引,它的限制能力也远远低于多列索引。 最左前缀 多列索引有一个特点,即最左前缀(Leftmost Prefixing)。假如有一个多列索引为key(firstname lastname age),当搜索条件是以下各种列的组合和顺序时,MySQL将使用该多列索引: firstname,lastname,age firstname,lastname firstname 也就是说,相当于还建立了key(firstname lastname)和key(firstname)。 索引主要用于下面的操作: Ø 快速找出匹配一个WHERE子句的行。 Ø 删除行。当执行联接时,从其它表检索行。 Ø 对具体有索引的列key_col找出MAX()或MIN()值。由预处理器进行优化,检查是否对索引中在key_col之前发生所有关键字元素使用了WHERE key_part_# = constant。在这种情况下,MySQL为每个MIN()或MAX()表达式执行一次关键字查找,并用常数替换它。如果所有表达式替换为常量,查询立即返回。例如: SELECT MIN(key2), MAX (key2) FROM tb WHERE key1=10; Ø 如果对一个可用关键字的最左面的前缀进行了排序或分组(例如,ORDER BY key_part_1,key_part_2),排序或分组一个表。如果所有关键字元素后面有DESC,关键字以倒序被读取。 Ø 在一些情况中,可以对一个查询进行优化以便不用查询数据行即可以检索值。如果查询只使用来自某个表的数字型并且构成某些关键字的最左面前缀的列,为了更快,可以从索引树检索出值。 SELECT key_part3 FROM tb WHERE key_part1=1 有时MySQL不使用索引,即使有可用的索引。一种情形是当优化器估计到使用索引将需要MySQL访问表中的大部分行时。(在这种情况下,表扫描可能会更快些)。然而,如果此类查询使用LIMIT只搜索部分行,MySQL则使用索引,因为它可以更快地找到几行并在结果中返回。例如: 合理的建立索引的建议: (1) 越小的数据类型通常更好:越小的数据类型通常在磁盘、内存和CPU缓存中都需要更少的空间,处理起来更快。 (2) 简单的数据类型更好:整型数据比起字符,处理开销更小,因为字符串的比较更复杂。在MySQL中,应该用内置的日期和时间数据类型,而不是用字符串来存储时间;以及用整型数据类型存储IP地址。 (3) 尽量避免NULL:应该指定列为NOT NULL,除非你想存储NULL。在MySQL中,含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以及比较运算更加复杂。你应该用0、一个特殊的值或者一个空串代替空值 这部分是关于索引和写SQL语句时应当注意的一些琐碎建议和注意点。 1. 当结果集只有一行数据时使用LIMIT 1 2. 避免SELECT *,始终指定你需要的列 从表中读取越多的数据,查询会变得更慢。他增加了磁盘需要操作的时间,还是在数据库服务器与WEB服务器是独立分开的情况下。你将会经历非常漫长的网络延迟,仅仅是因为数据不必要的在服务器之间传输。 3. 使用连接(JOIN)来代替子查询(Sub-Queries) 连接(JOIN).. 之所以更有效率一些,是因为MySQL不需要在内存中创建临时表来完成这个逻辑上的需要两个步骤的查询工作。 4. 使用ENUM、CHAR 而不是VARCHAR,使用合理的字段属性长度 5. 尽可能的使用NOT NULL 6. 固定长度的表会更快 7. 拆分大的DELETE 或INSERT 语句 8. 查询的列越小越快 Where条件 在查询中,WHERE条件也是一个比较重要的因素,尽量少并且是合理的where条件是很重要的,尽量在多个条件的时候,把会提取尽量少数据量的条件放在前面,减少后一个where条件的查询时间。 有些where条件会导致索引无效: Ø where子句的查询条件里有!=,MySQL将无法使用索引。 Ø where子句使用了Mysql函数的时候,索引将无效,比如:select * from tb where left(name, 4) = ‘xxx’ Ø 使用LIKE进行搜索匹配的时候,这样索引是有效的:select * from tbl1 where name like ‘xxx%’,而like ‘%xxx%’ 时索引无效 三、 配置优化 安装MySQL后,配置文件my.cnf在 /MySQL安装目录/share/mysql目录中,该目录中还包含多个配置文件可供参考,有my-large.cnf ,my-huge.cnf, my-medium.cnf,my-small.cnf,分别对应大中小型数据库应用的配置。win环境下即存在于MySQL安装目录中的.ini文件。 下面列出了对性能优化影响较大的主要变量,主要分为连接请求的变量和缓冲区变量。 1. 连接请求的变量: 1) max_connections MySQL的最大连接数,增加该值增加mysqld 要求的文件描述符的数量。如果服务器的并发连接请求量比较大,建议调高此值,以增加并行连接数量,当然这建立在机器能支撑的情况下,因为如果连接数越多,介于MySQL会为每个连接提供连接缓冲区,就会开销越多的内存,所以要适当调整该值,不能盲目提高设值。 数值过小会经常出现ERROR 1040: Too many connections错误,可以过’conn%’通配符查看当前状态的连接数量,以定夺该值的大小。 show variables like ‘max_connections’ 最大连接数 show status like ‘max_used_connections’响应的连接数 如下: mysql> show variables like ‘max_connections‘; +———————–+——-+ | Variable_name | Value | +———————–+——-+ | max_connections | 256 | +———————–+——-+ mysql> show status like ‘max%connections‘; +———————–+——-+ | Variable_name | Value | +—————————-+——-+ | max_used_connections | 256| +—————————-+——-+ max_used_connections / max_connections * 100% (理想值≈ 85%) 如果max_used_connections跟max_connections相同 那么就是max_connections设置过低或者超过服务器负载上限了,低于10%则设置过大。 2) back_log MySQL能暂存的连接数量。当主要MySQL线程在一个很短时间内得到非常多的连接请求,这就起作用。如果MySQL的连接数据达到max_connections时,新来的请求将会被存在堆栈中,以等待某一连接释放资源,该堆栈的数量即back_log,如果等待连接的数量超过back_log,将不被授予连接资源。 back_log值指出在MySQL暂时停止回答新请求之前的短时间内有多少个请求可以被存在堆栈中。只有如果期望在一个短时间内有很多连接,你需要增加它,换句话说,这值对到来的TCP/IP连接的侦听队列的大小。 当观察你主机进程列表(mysql> show full processlist),发现大量264084 | unauthenticated user | xxx.xxx.xxx.xxx | NULL | Connect | NULL | login | NULL 的待连接进程时,就要加大back_log 的值了。 默认数值是50,可调优为128,对于Linux系统设置范围为小于512的整数。 3) interactive_timeout 一个交互连接在被服务器在关闭前等待行动的秒数。一个交互的客户被定义为对mysql_real_connect()使用CLIENT_INTERACTIVE 选项的客户。 默认数值是28800,可调优为7200。 2. 缓冲区变量 全局缓冲: 4) key_buffer_size key_buffer_size指定索引缓冲区的大小,它决定索引处理的速度,尤其是索引读的速度。通过检查状态值Key_read_requests和Key_reads,可以知道key_buffer_size设置是否合理。比例key_reads / key_read_requests应该尽可能的低,至少是1:100,1:1000更好(上述状态值可以使用SHOW STATUS LIKE ‘key_read%’获得)。 key_buffer_size只对MyISAM表起作用。即使你不使用MyISAM表,但是内部的临时磁盘表是MyISAM表,也要使用该值。可以使用检查状态值created_tmp_disk_tables得知详情。 举例如下: mysql> show variables like ‘key_buffer_size‘; +——————-+————+ | Variable_name | Value | +———————+————+ | key_buffer_size | 536870912 | +———— ———-+————+ key_buffer_size为512MB,我们再看一下key_buffer_size的使用情况: mysql> show global status like ‘key_read%‘; +————————+————-+ | Variable_name | Value | +————————+————-+ | Key_read_requests| 27813678764 | | Key_reads | 6798830 | +————————+————-+ 一共有27813678764个索引读取请求,有6798830个请求在内存中没有找到直接从硬盘读取索引,计算索引未命中缓存的概率: key_cache_miss_rate =Key_reads / Key_read_requests * 100%,设置在1/1000左右较好 默认配置数值是8388600(8M),主机有4GB内存,可以调优值为268435456(256MB)。 5) query_cache_size 使用查询缓冲,MySQL将查询结果存放在缓冲区中,今后对于同样的SELECT语句(区分大小写),将直接从缓冲区中读取结果。 通过检查状态值Qcache_*,可以知道query_cache_size设置是否合理(上述状态值可以使用SHOW STATUS LIKE ‘Qcache%’获得)。如果Qcache_lowmem_prunes的值非常大,则表明经常出现缓冲不够的情况,如果Qcache_hits的值也非常大,则表明查询缓冲使用非常频繁,此时需要增加缓冲大小;如果Qcache_hits的值不大,则表明你的查询重复率很低,这种情况下使用查询缓冲反而会影响效率,那么可以考虑不用查询缓冲。此外,在SELECT语句中加入SQL_NO_CACHE可以明确表示不使用查询缓冲。 与查询缓冲有关的参数还有query_cache_type、query_cache_limit、query_cache_min_res_unit。 query_cache_type指定是否使用查询缓冲,可以设置为0、1、2,该变量是SESSION级的变量。 query_cache_limit指定单个查询能够使用的缓冲区大小,缺省为1M。 query_cache_min_res_unit是在4.1版本以后引入的,它指定分配缓冲区空间的最小单位,缺省为4K。检查状态值Qcache_free_blocks,如果该值非常大,则表明缓冲区中碎片很多,这就表明查询结果都比较小,此时需要减小query_cache_min_res_unit。 举例如下: mysql> show global status like ‘qcache%‘; +——————————-+—————–+ | Variable_name | Value | +——————————-+—————–+ | Qcache_free_blocks | 22756 | | Qcache_free_memory | 76764704 | | Qcache_hits | 213028692 | | Qcache_inserts | 208894227 | | Qcache_lowmem_prunes | 4010916 | | Qcache_not_cached | 13385031 | | Qcache_queries_in_cache | 43560 | | Qcache_total_blocks | 111212 | +——————————-+—————–+ mysql> show variables like ‘query_cache%‘; +————————————–+————–+ | Variable_name | Value | +————————————–+———–+ | query_cache_limit | 2097152 | | query_cache_min_res_unit | 4096 | | query_cache_size | 203423744 | | query_cache_type | ON | | query_cache_wlock_invalidate | OFF | +————————————–+—————+ 查询缓存碎片率= Qcache_free_blocks / Qcache_total_blocks * 100% 如果查询缓存碎片率超过20%,可以用FLUSH QUERY CACHE整理缓存碎片,或者试试减小query_cache_min_res_unit,如果你的查询都是小数据量的话。 查询缓存利用率= (query_cache_size – Qcache_free_memory) / query_cache_size * 100% 查询缓存利用率在25%以下的话说明query_cache_size设置的过大,可适当减小;查询缓存利用率在80%以上而且Qcache_lowmem_prunes > 50的话说明query_cache_size可能有点小,要不就是碎片太多。 查询缓存命中率= (Qcache_hits – Qcache_inserts) / Qcache_hits * 100% 示例服务器查询缓存碎片率=20.46%,查询缓存利用率=62.26%,查询缓存命中率=1.94%,命中率很差,可能写操作比较频繁吧,而且可能有些碎片。 每个连接的缓冲 6) record_buffer_size 每个进行一个顺序扫描的线程为其扫描的每张表分配这个大小的一个缓冲区。如果你做很多顺序扫描,你可能想要增加该值。 默认数值是131072(128K),可改为16773120 (16M) 7) read_rnd_buffer_size 随机读缓冲区大小。当按任意顺序读取行时(例如,按照排序顺序),将分配一个随机读缓存区。进行排序查询时,MySQL会首先扫描一遍该缓冲,以避免磁盘搜索,提高查询速度,如果需要排序大量数据,可适当调高该值。但MySQL会为每个客户连接发放该缓冲空间,所以应尽量适当设置该值,以避免内存开销过大。 一般可设置为16M 8) sort_buffer_size 每个需要进行排序的线程分配该大小的一个缓冲区。增加这值加速ORDER BY或GROUP BY操作。 默认数值是2097144(2M),可改为16777208 (16M)。 9) join_buffer_size 联合查询操作所能使用的缓冲区大小 record_buffer_size,read_rnd_buffer_size,sort_buffer_size,join_buffer_size为每个线程独占,也就是说,如果有100个线程连接,则占用为16M*100 10) table_cache 表高速缓存的大小。每当MySQL访问一个表时,如果在表缓冲区中还有空间,该表就被打开并放入其中,这样可以更快地访问表内容。通过检查峰值时间的状态值Open_tables和Opened_tables,可以决定是否需要增加table_cache的值。如果你发现open_tables等于table_cache,并且opened_tables在不断增长,那么你就需要增加table_cache的值了(上述状态值可以使用SHOW STATUS LIKE ‘Open%tables’获得)。注意,不能盲目地把table_cache设置成很大的值。如果设置得太高,可能会造成文件描述符不足,从而造成性能不稳定或者连接失败。 1G内存机器,推荐值是128-256。内存在4GB左右的服务器该参数可设置为256M或384M。 11) max_heap_table_size 用户可以创建的内存表(memory table)的大小。这个值用来计算内存表的最大行数值。这个变量支持动态改变,即set @max_heap_table_size=# 这个变量和tmp_table_size一起限制了内部内存表的大小。如果某个内部heap(堆积)表大小超过tmp_table_size,MySQL可以根据需要自动将内存中的heap表改为基于硬盘的MyISAM表。 12) tmp_table_size 通过设置tmp_table_size选项来增加一张临时表的大小,例如做高级GROUP BY操作生成的临时表。如果调高该值,MySQL同时将增加heap表的大小,可达到提高联接查询速度的效果,建议尽量优化查询,要确保查询过程中生成的临时表在内存中,避免临时表过大导致生成基于硬盘的MyISAM表。 mysql> show global status like ‘created_tmp%‘; +——————————–+———+ | Variable_name | Value | +———————————-+———+ | Created_tmp_disk_tables | 21197 | | Created_tmp_files | 58 | | Created_tmp_tables | 1771587 | +——————————–+———–+ 每次创建临时表,Created_tmp_tables增加,如果临时表大小超过tmp_table_size,则是在磁盘上创建临时表,Created_tmp_disk_tables也增加,Created_tmp_files表示MySQL服务创建的临时文件文件数,比较理想的配置是: Created_tmp_disk_tables / Created_tmp_tables * 100% <= 25%比如上面的服务器Created_tmp_disk_tables / Created_tmp_tables * 100% =1.20%,应该相当好了 默认为16M,可调到64-256最佳,线程独占,太大可能内存不够I/O堵塞 13) thread_cache_size 可以复用的保存在中的线程的数量。如果有,新的线程从缓存中取得,当断开连接的时候如果有空间,客户的线置在缓存中。如果有很多新的线程,为了提高性能可以这个变量值。 通过比较 Connections和Threads_created状态的变量,可以看到这个变量的作用。 默认值为110,可调优为80。 14) thread_concurrency 推荐设置为服务器 CPU核数的2倍,例如双核的CPU, 那么thread_concurrency的应该为4;2个双核的cpu, thread_concurrency的值应为8。默认为8 15) wait_timeout 指定一个请求的最大连接时间,对于4GB左右内存的服务器可以设置为5-10。 3. 配置InnoDB的几个变量 innodb_buffer_pool_size 对于InnoDB表来说,innodb_buffer_pool_size的作用就相当于key_buffer_size对于MyISAM表的作用一样。InnoDB使用该参数指定大小的内存来缓冲数据和索引。对于单独的MySQL数据库服务器,最大可以把该值设置成物理内存的80%。 根据MySQL手册,对于2G内存的机器,推荐值是1G(50%)。 innodb_flush_log_at_trx_commit 主要控制了innodb将log buffer中的数据写入日志文件并flush磁盘的时间点,取值分别为0、1、2三个。0,表示当事务提交时,不做日志写入操作,而是每秒钟将log buffer中的数据写入日志文件并flush磁盘一次;1,则在每秒钟或是每次事物的提交都会引起日志文件写入、flush磁盘的操作,确保了事务的ACID;设置为2,每次事务提交引起写入日志文件的动作,但每秒钟完成一次flush磁盘操作。 实际测试发现,该值对插入数据的速度影响非常大,设置为2时插入10000条记录只需要2秒,设置为0时只需要1秒,而设置为1时则需要229秒。因此,MySQL手册也建议尽量将插入操作合并成一个事务,这样可以大幅提高速度。 根据MySQL手册,在允许丢失最近部分事务的危险的前提下,可以把该值设为0或2。 innodb_log_buffer_size log缓存大小,一般为1-8M,默认为1M,对于较大的事务,可以增大缓存大小。 可设置为4M或8M。 innodb_additional_mem_pool_size 该参数指定InnoDB用来存储数据字典和其他内部数据结构的内存池大小。缺省值是1M。通常不用太大,只要够用就行,应该与表结构的复杂度有关系。如果不够用,MySQL会在错误日志中写入一条警告信息。 根据MySQL手册,对于2G内存的机器,推荐值是20M,可适当增加。 innodb_thread_concurrency=8 推荐设置为 2*(NumCPUs+NumDisks),默认一般为8
大数据我们都知道hadoop,可是还会各种各样的技术进入我们的视野:Spark,Storm,impala,让我们都反映不过来。为了能够更好的架构大数据项目,这里整理一下,供技术人员,项目经理,架构师选择合适的技术,了解大数据各种技术之间的关系,选择合适的语言。 我们可以带着下面问题来阅读本文章: 1.hadoop都包含什么技术? 2.Cloudera公司与hadoop的关系是什么,都有什么产品,产品有什么特性? 3.Spark与hadoop的关联是什么? 4.Storm与hadoop的关联是什么? hadoop家族 创始人:Doug Cutting 整个Hadoop家族由以下几个子项目组成: Hadoop Common: Hadoop体系最底层的一个模块,为Hadoop各子项目提供各 种工具,如:配置文件和日志操作等。 HDFS: 是Hadoop应用程序中主要的分布式储存系统, HDFS集群包含了一个NameNode(主节点),这个节点负责管理所有文件系统的元数据及存储了真实数据的DataNode(数据节点,可以有很多)。HDFS针对海量数据所设计,所以相比传统文件系统在大批量小文件上的优化,HDFS优化的则是对小批量大型文件的访问和存储。 MapReduce: 是一个软件框架,用以轻松编写处理海量(TB级)数据的并行应用程序,以可靠和容错的方式连接大型集群中上万个节点(商用硬件)。 Hive: Apache Hive是Hadoop的一个数据仓库系统,促进了数据的综述(将结构化的数据文件映射为一张数据库表)、即席查询以及存储在Hadoop兼容系统中的大型数据集分析。Hive提供完整的SQL查询功能——HiveQL语言,同时当使用这个语言表达一个逻辑变得低效和繁琐时,HiveQL还允许传统的Map/Reduce程序员使用自己定制的Mapper和Reducer。hive类似CloudBase,基于hadoop分布式计算平台上的提供data warehouse的sql功能的一套软件。使得存储在hadoop里面的海量数据 的汇总,即席查询简单化。 Pig: Apache Pig是一个用于大型数据集分析的平台,它包含了一个用于数据分析应用的高级语言以及评估这些应用的基础设施。Pig应用的闪光特性在于它们的结构经得起大量的并行,也就是说让它们支撑起非常大的数据集。Pig的基础设施层包含了产生Map-Reduce任务的编译器。Pig的语言层当前包含了一个原生语言——Pig Latin,开发的初衷是易于编程和保证可扩展性。 Pig是SQL-like语言,是在MapReduce上构建的一种高级查询语言,把一些运算编译进MapReduce模型的Map和Reduce中,并且用户可以定义自己的功能。Yahoo网格运算部门开发的又一个克隆Google的项目Sawzall。 HBase: Apache HBase是Hadoop数据库,一个分布式、可扩展的大数据存储。它提供了大数据集上随机和实时的读/写访问,并针对了商用服务器集群上的大型表格做出优化——上百亿行,上千万列。其核心是Google Bigtable论文的开源实现,分布式列式存储。就像Bigtable利用GFS(Google File System)提供的分布式数据存储一样,它是Apache Hadoop在HDFS基础上提供的一个类Bigatable。 ZooKeeper: Zookeeper是Google的Chubby一个开源的实现。它是一个针对大型分布式系统的可靠协调系统,提供的功能包括:配置维护、名字服务、 分布式同步、组服务等。ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。 Avro: Avro是doug cutting主持的RPC项目,有点类似Google的protobuf和Facebook的thrift。avro用来做以后hadoop的RPC,使hadoop的RPC模块通信速度更快、数据结构更紧凑。 Sqoop: Sqoop是一个用来将Hadoop和关系型数据库中的数据相互转移的工具,可以将一个关系型数据库中数据导入Hadoop的HDFS中,也可以将HDFS中数据导入关系型数据库中。 Mahout: Apache Mahout是个可扩展的机器学习和数据挖掘库,当前Mahout支持主要的4个用例: 推荐挖掘:搜集用户动作并以此给用户推荐可能喜欢的事物。 聚集:收集文件并进行相关文件分组。 分类:从现有的分类文档中学习,寻找文档中的相似特征,并为无标签的文档进行正确的归类。 频繁项集挖掘:将一组项分组,并识别哪些个别项会经常一起出现。 Cassandra: Apache Cassandra是一个高性能、可线性扩展、高有效性数据库,可以运行在商用硬件或云基础设施上打造完美的任务关键性数据平台。在横跨数据中心的复制中,Cassandra同类最佳,为用户提供更低的延时以及更可靠的灾难备份。通过log-structured update、反规范化和物化视图的强支持以及强大的内置缓存,Cassandra的数据模型提供了方便的二级索引(column indexe)。 Chukwa: Apache Chukwa是个开源的数据收集系统,用以监视大型分布系统。建立于HDFS和Map/Reduce框架之上,继承了Hadoop的可扩展性和稳定性。Chukwa同样包含了一个灵活和强大的工具包,用以显示、监视和分析结果,以保证数据的使用达到最佳效果。 Ambari: Apache Ambari是一个基于web的工具,用于配置、管理和监视Apache Hadoop集群,支持Hadoop HDFS,、Hadoop MapReduce、Hive、HCatalog,、HBase、ZooKeeper、Oozie、Pig和Sqoop。Ambari同样还提供了集群状况仪表盘,比如heatmaps和查看MapReduce、Pig、Hive应用程序的能力,以友好的用户界面对它们的性能特性进行诊断。 HCatalog Apache HCatalog是Hadoop建立数据的映射表和存储管理服务,它包括: 提供一个共享模式和数据类型机制。 提供一个抽象表,这样用户就不需要关注数据存储的方式和地址。 为类似Pig、MapReduce及Hive这些数据处理工具提供互操作性。 Chukwa: Chukwa是基于Hadoop的大集群监控系统,由yahoo贡献。 Cloudera系列产品: 创始组织:Cloudera公司 1.Cloudera Manager: 有四大功能 (1)管理 (2)监控 (3)诊断 (4)集成 2.Cloudera CDH:英文名称:CDH (Cloudera’s Distribution, including Apache Hadoop) Cloudera对hadoop做了相应的改变。 Cloudera公司的发行版,我们将该版本称为CDH(Cloudera Distribution Hadoop)。 3.Cloudera Flume Flume是Cloudera提供的日志收集系统,Flume支持在日志系统中定制各类数据发送方,用于收集数据; Flume是Cloudera提供的一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统,Flume支持在日志系统中定制各类数据发送方,用于收集数据;同时,Flume提供对数据进行简单处理,并写到各种数据接受方(可定制)的能力。 Flume最早是Cloudera提供的日志收集系统,目前是Apache下的一个孵化项目,Flume支持在日志系统中定制各类数据发送方,用于收集数据;同时,Flume提供对数据进行简单处理,并写到各种数据接受方(可定制)的能力 Flume提供了从console(控制台)、RPC(Thrift-RPC)、text(文件)、tail(UNIX tail)、syslog(syslog日志系统,支持TCP和UDP等2种模式),exec(命令执行)等数据源上收集数据的能力。 Flume采用了多Master的方式。为了保证配置数据的一致性,Flume[1]引入了ZooKeeper,用于保存配置数据,ZooKeeper本身可保证配置数据的一致性和高可用,另外,在配置数据发生变化时,ZooKeeper可以通知Flume Master节点。Flume Master间使用gossip协议同步数据。 4.Cloudera Impala Cloudera Impala对你存储在Apache Hadoop在HDFS,HBase的数据提供直接查询互动的SQL。除了像Hive使用相同的统一存储平台,Impala也使用相同的元数据,SQL语法(Hive SQL),ODBC驱动程序和用户界面(Hue Beeswax)。Impala还提供了一个熟悉的面向批量或实时查询和统一平台。 5.Cloudera hue Hue是cdh专门的一套web管理器,它包括3个部分hue ui,hue server,hue db。hue提供所有的cdh组件的shell界面的接口。你可以在hue编写mr,查看修改hdfs的文件,管理hive的元数据,运行Sqoop,编写Oozie工作流等大量工作。 Spark 创始组织:加州大学伯克利分校 AMP 实验室 (Algorithms, Machines, and People Lab) 开发 Spark 是一种与 Hadoop 相似的开源集群计算环境,但是两者之间还存在一些不同之处,这些有用的不同之处使 Spark 在某些工作负载方面表现得更加优越,换句话说,Spark 启用了内存分布数据集,除了能够提供交互式查询外,它还可以优化迭代工作负载。 Spark 是在 Scala 语言中实现的,它将 Scala 用作其应用程序框架。与 Hadoop 不同,Spark 和 Scala 能够紧密集成,其中的 Scala 可以像操作本地集合对象一样轻松地操作分布式数据集。 尽管创建 Spark 是为了支持分布式数据集上的迭代作业,但是实际上它是对 Hadoop 的补充,可以在 Hadoo 文件系统中并行运行。通过名为 Mesos 的第三方集群框架可以支持此行为。Spark 由加州大学伯克利分校 AMP 实验室 (Algorithms, Machines, and People Lab) 开发,可用来构建大型的、低延迟的数据分析应用程序。 Storm 创始人:Twitter Twitter将Storm正式开源了,这是一个分布式的、容错的实时计算系统,它被托管在GitHub上,遵循 Eclipse Public License 1.0。Storm是由BackType开发的实时处理系统,BackType现在已在Twitter麾下。GitHub上的最新版本是Storm 0.5.2,基本是用Clojure写的。 ——转自炼数成金
以下5种语言 NODE、LUA、Python、Ruby、R ,哪个在2014年的应用前景会更好? 我毫不犹豫的选择R。R不仅是2014年,也是以后更长一段时间的主角。 1. 我的编程背景 本人程序员、架构师,从编程入门到今天,一直深信着Java是改变世界的语言,Java已经做到了,而且一直很辉煌。但当Java的世界越来越大,变得无所不能的时候,反而不够专业,给了其他语言发展的机会。 本次要比较要5种编程语言(NODE,LUA,Python,Ruby,R),这些都是非常优秀的,在特定领域发展壮大的语言。 我已使用Java语言 11年,R语言 3年,Node 1年,对于本次问题 “哪个语言在2014年的应用前景会更好?”,我选择R语言。 2. 为什么我会选择R? 我会从下面的几个方面,来说明我选择R的原因。 1). R的基因 R是统计学家发明的语言,天生具有统计的基因。 从我开始学习R语言,我就开始了知识的跨界思考。统计基于概率论,概率论又基于数学,用计算机的方式编程,解决某个领域的实际问题。简单一算,4个学科知识的交集,决定着我们解决问题的能力。统计的基因,让R语言与众不同! 2). R的发展 R一直在小众领域成长着,最早也只有统计学家在用,主要用R来代替SAS做统计计算。时代在进步,随着大数据的爆发,R终于在这一波浪潮中,被工业 界所发现。然后,有越来越多的工程背景的人加入到这个圈子,对R计算引擎,R的性能,R的各种程序包进行改进和升级,让R获得了新生。 我们现在用到的R语言软件,已经越来越接近工业软件的标准了。由工程师推动的R的发展速度,远远地超过了由统计学家推动的步伐。随着人们对数据分析要求的进一步增加,R会以更快的脚步继续发展,将成为免费的、开源的、数据分析软件的代名词。 3). R的社区和资源 R的发展,离不开R的社区支持。当然,我不得不承认R的官方社区,从Web页上看起来太简陋了,稍微调整一下CSS样式表,都会比现在好看很多。也许这种简单、无修饰也是统计学家的基因吧。 在R的社区中,我们可以下载到R语言软件,R的第三方软件包,和R的其他支持软件。可以找到开发者论坛,R-Journal列表,软件包列表,R语言图书列表,R用户组等的信息,同其他语言的社区资源一样丰富。 R是自由软件,开发者可以开发自己的软件包,封装自己的功能,然后在CRAN上面发布。截止到2014年2月,共有5236个R包在CRAN上面发布。 可能很多人会说只有5236个包,数量太少了。这是因为CRAN是需要提交申请的,R语言小组审核,检查后再会发布的出来。而且审核非常严格的,高 质量是发布一个新的R包基本要求。由于CRAN过于严格的审查,让很多的开发者选择在RForge上发布,还有些R包是基于Github发布的,我也在 github上面发布了自己的R包:https://github.com/bsspirit/chinaWeather。 R官方地址:http://www.r-project.org/ R开发者论坛:http://r.789695.n4.nabble.com/ CRAN:http://cran.rstudio.com/ RForge:https://r-forge.r-project.org/ 4). R的哲学 每种语言都有自己的设计理念和哲学,而我体会的R的哲学,就是“静下心做事情”。 R不需要很长的代码,R也不需要设计模式。一个函数调用,传几个参数,就能实现一个复杂的统计模型。我们需要思考,用什么模型,传什么参数,而不是怎么进行程序设计。 我们可能会用R实现 “从一个数学公式,变成一个统计模型” 的过程,我们也可能会考虑 “如何让一个分类器结果更准确”,但我们不会思考 “时间复杂度是多少,空间复杂度是多少”。 R的哲学,可以让你把数学和统计学的知识,变成计算模型,这也是R的基因所决定的。 5). R的使用者 R语言早期主要是学术界统计学家在用,在各种不同的领域,包括统计分析,应用数学,计量经济,金融分析,财经分析,人文科学,数据挖掘,人工智能,生物信息学,生物制药,全球地理科学,数据可视化等等。 近些年来,由互联网引发的大数据革命,才让工业界的人,开始认识R,加入R。当越来越多的有工程背景的人,加入到R语言使用者的队伍后,R才开始像着全领域发展,逐步实现工业化的要求。 RevolutionAnalytics公司的RHadoop产品,让R可以直接调用Hadoop集群资源 RStudio公司的RStudio产品,给了我们对于编辑软件新的认识 RMySQL, ROracle, RJDBC 打通了R和数据库访问通道 rmongodb, rredis, RHive, rhbase, RCassandra 打通过R和NoSQL的访问通道 Rmpi, snow 打通了单机多核并行计算的通道 Rserve,rwebsocket 打通了R语言的跨平台通信的通道 R不仅是学术界的语言,更将成为工业界必备的语言。 6). R的语法 R是面向对象语言,语法如同Python。但R的语法很自由,很多函数的名字,看起来都是那么随意,这也是R的哲学的一部分吧! 看到这样的赋值语法,有其他语言基础的程序员,肯定会崩溃的。 > a<-c(1,2,3,4)->b > a [1] 1 2 3 4 > b [1] 1 2 3 4 随机取正态分布N(0,1)的10个数,又是这么的简单。 > rnorm(10) [1] -0.694541401 1.877780959 -0.178608091 0.004362026 [5] 0.836891967 1.794961298 0.115284187 0.155175219 [9] 0.464028612 -0.842569561 用R画鸢尾花的数据集的散点图,非常好的可视化效果 > data(iris) #加载数据集 > head(iris) #查看前6行数据集 Sepal.Length Sepal.Width Petal.Length Petal.Width Species 1 5.1 3.5 1.4 0.2 setosa 2 4.9 3.0 1.4 0.2 setosa 3 4.7 3.2 1.3 0.2 setosa 4 4.6 3.1 1.5 0.2 setosa 5 5.0 3.6 1.4 0.2 setosa 6 5.4 3.9 1.7 0.4 setosa > plot(iris) #画图 正是因为R自由哲学,让R的语法独特而简洁,我已经喜欢上这种哲学了。 7). R的思维模式 R语言让我跳出了原有思维定式。使用R语言,我们应该从统计学的角度想问题,而不是计算机的思维模式。 R语言是直接面向数据的语言。在我们的日常生活中,无论做什么事情都会产生数据,上网有浏览数据,买东西有消费数据,就算什么都不干,也会受大气PM2.5的影响。利用R语言,我可以直接分析这些数据。 面向什么业务,就分析什么数据,不需要从产品经理向程序员的角色转换,不需要考虑有什么功能,更不需要考虑程序设计的事。 跳出程序员的思维模式,你所能认知的东西会更多,找到更适合自己的定位。 8). R解决的问题 当数据成为生产资料的时候,R就是为人们能运用生产资料创造价值的生产工具,R语言主要解决的是数据的问题。 在很长期的历史时期,人类产生的数据都没有自互联网诞生以来产生的数据多;当Hadoop帮助人们解决了大数据存储的问题后,如何发现数据的价值,成为当前最火的话题。R语言的统计分析能力,就是数据分析最好的工具。 所以,R要解决的问题,就是大数据时代的问题,是时代赋予的任务。 9). R的不足 前面说了太多R的优点了,R也有很多不足之处。 R语言是统计学家编写的软件,并不如软件工程师编写的软件那么健壮。 R语言软件的性能,存在一些问题。 R语言很自由,语法命名不太规范,需要花时间熟悉。 R语言结合了很多数学、概率、统计的基础知识,学起来有一定门槛。 R的这些不足,都是可以克服的。当有更多的工程背景的人加入的时候,R语言会比现在更强大,帮助使用者创造更多的价值。 3. R的应用前景 R可以做所有SAS做的事情。 R应用最热门的领域: 统计分析:包括统计分布,假设检验,统计建模 金融分析:量化策略,投资组合,风险控制,时间序列,波动率 数据挖掘:数据挖掘算法,数据建模,机器学习 互联网:推荐系统,消费预测,社交网络 生物信息学:DNA分析,物种分析 生物制药:生存分析,制药过程管理 全球地理科学:天气,气候,遥感数据 数据可视化:静态图,可交互的动态图,社交图,地图,热图,与各种Javascript库的集成 R有着非常广阔的应用前景,而且R也将成为新一代的最有能力创造价值的工具。 4. 时代赋予R的任务 R语言是在大数据时代被工业界了解和认识的语言,R语言被时代赋予了,挖掘数据价值,发现数据规律,创造数据财富的任务。 R语言也是帮助人们发挥智慧和创造力的最好的生产工具,我们不仅要学好R语言,还要用好R语言,为社会注入更多的创新的生产力。 所以,通过上面的几节内容所有的文字描述,我认为“R是最值得学习的编程语言”。不论你还在读书,还是已经工作,掌握R语言这个工具,找最适合自己的位置,前途将无限量。 最后总结:在这5种语言中,R是最特殊的,R被赋予了与其他语言不同的使命。R的基因决定了,R将成为2014年,也可能是以后更长一段时间的主角。
看数据挖掘方面的算法理论时经常感觉一些公式的推导过程如天书一般,例如看svm的数学证明,EM算法..,感觉知识跳跃比较大,那么数据挖掘系统的学习过程是怎么样? 磨刀不误砍柴工。在学习数据挖掘之前应该明白几点: 数据挖掘目前在中国的尚未流行开,犹如屠龙之技。 数据初期的准备通常占整个数据挖掘项目工作量的70%左右。 数据挖掘本身融合了统计学、数据库和机器学习等学科,并不是新的技术。 数据挖掘技术更适合业务人员学习(相比技术人员学习业务来的更高效) 数据挖掘适用于传统的BI(报表、OLAP等)无法支持的领域。 数据挖掘项目通常需要重复一些毫无技术含量的工作。 如果你阅读了以上内容觉得可以接受,那么继续往下看。 学习一门技术要和行业靠拢,没有行业背景的技术如空中楼阁。技术尤其是计算机领域的技术发展是宽泛且快速更替的(十年前做网页设计都能成立公司),一般人 没有这个精力和时间全方位的掌握所有技术细节。但是技术在结合行业之后就能够独当一面了,一方面有利于抓住用户痛点和刚性需求,另一方面能够累计行业经 验,使用互联网思维跨界让你更容易取得成功。不要在学习技术时想要面面俱到,这样会失去你的核心竞争力。 一、目前国内的数据挖掘人员工作领域大致可分为三类。 数据分析师:在拥有行业数据的电商、金融、电信、咨询等行业里做业务咨询,商务智能,出分析报告。 数据挖掘工程师:在多媒体、电商、搜索、社交等大数据相关行业里做机器学习算法实现和分析。 科学研究方向:在高校、科研单位、企业研究院等高大上科研机构研究新算法效率改进及未来应用。 二、说说各工作领域需要掌握的技能。 (1).数据分析师 需要有深厚的数理统计基础,但是对程序开发能力不做要求。 需要熟练使用主流的数据挖掘(或统计分析)工具如Business Analytics and Business Intelligence Software(SAS)、SPSS、EXCEL等。 需要对与所在行业有关的一切核心数据有深入的理解,以及一定的数据敏感性培养。 经典图书推荐:《概率论与数理统计》、《统计学》推荐David Freedman版、《业务建模与数据挖掘》、《数据挖掘导论》、《SAS编程与数据挖掘商业案例》、《Clementine数据挖掘方法及应用 》、《Excel 2007 VBA参考大全》、《IBM SPSS Statistics 19 Statistical Procedures Companion》等。 经典课程推荐:《概率论与数理统计》、《数据分析与R语言》、《SPSS统计分析及数据挖掘》、《excel2010在实践中的应用》、《R语言进阶——数据展现》、《SPSS数据挖掘方法概述》、《SAS入门到精通》 (2).数据挖掘工程师 需要理解主流机器学习算法的原理和应用。 需要熟悉至少一门编程语言如(Python、C、C++、Java、Delphi等)。 需要理解数据库原理,能够熟练操作至少一种数据库(Mysql、SQL、DB2、Oracle等),能够明白MapReduce的原理操作以及熟练使用Hadoop系列工具更好。 经典图书推荐:《数据挖掘概念与技术》、《机器学习实战》、《人工智能及其应用》、《数据库系统概论》、《算法导论》、《Web数据挖掘》、《 Python标准库》、《thinking in Java》、《Thinking in C++》、《数据结构》等。 经典课程推荐:《SPSS统计分析及数据挖掘》、《R七种武器之金融数据分析quantmod》 (3).科学研究方向 需要深入学习数据挖掘的理论基础,包括关联规则挖掘 (Apriori和FPTree)、分类算法(C4.5、KNN、Logistic Regression、SVM等) 、聚类算法 (Kmeans、Spectral Clustering)。目标可以先吃透数据挖掘10大算法各自的使用情况和优缺点。 相对SAS、SPSS来说R语言更适合科研人员The R Project for Statistical Computing,因为R软件是完全免费的,而且开放的社区环境提供多种附加工具包支持,更适合进行统计计算分析研究。虽然目前在国内流行度不高,但是 强烈推荐。 可以尝试改进一些主流算法使其更加快速高效,例如实现Hadoop平台下的SVM云算法调用平台–web 工程调用hadoop集群。 需要广而深的阅读世界著名会议论文跟踪热点技术。如KDD,ICML,IJCAI,Association for the Advancement of Artificial Intelligence,ICDM 等等;还有数据挖掘相关领域期刊:ACM Transactions on Knowledge Discovery from Data,IEEE Transactions on Knowledge and Data Engineering,Journal of Machine Learning Research Homepage,IEEE Xplore: Pattern Analysis and Machine Intelligence, IEEE Transactions on等。 可以尝试参加数据挖掘比赛培养全方面解决实际问题的能力。如Sig KDD ,Kaggle: Go from Big Data to Big Analytics等。 可以尝试为一些开源项目贡献自己的代码,比如Apache Mahout: Scalable machine learning and data mining ,myrrix等(具体可以在SourceForge或GitHub.上发现更多好玩的项目)。 经典图书推荐:《机器学习》 《模式分类》《统计学习理论的本质》《统计学习方法》《数据挖掘实用机器学习技术》《R语言实践》,英文素质是科研人才必备的《Machine Learning: A Probabilistic Perspective》《Scaling up Machine Learning : Parallel and Distributed Approaches》《Data Mining Using SAS Enterprise Miner : A Case Study Approach》《Python for Data Analysis》等。 经典课程推荐:《Hadoop数据分析平台》 三、以下是通信行业数据挖掘工程师的工作感受。 真正从数据挖掘项目实践的角度讲,沟通能力对挖掘的兴趣爱好是最重要的,有了爱好才可以愿意钻研,有了不错的沟通能力,才可以正确理解业务问题,才能正确 把业务问题转化成挖掘问题,才可以在相关不同专业人才之间清楚表达你的意图和想法,取得他们的理解和支持。所以我认为沟通能力和兴趣爱好是个人的数据挖掘 的核心竞争力,是很难学到的;而其他的相关专业知识谁都可以学,算不上个人发展的核心竞争力。 说到这里可能很多数据仓库专家、程序员、统计师等等都要扔砖头了,对不起,我没有别的意思,你们的专业对于数据挖掘都很重要,大家本来就是一个整体 的,但是作为单独一个个体的人来说,精力有限,时间有限,不可能这些领域都能掌握,在这种情况下,选择最重要的核心,我想应该是数据挖掘技能和相关业务能 力吧(从另外的一个极端的例子,我们可以看, 比如一个迷你型的挖掘项目,一个懂得市场营销和数据挖掘技能的人应该可以胜任。这其中他虽然不懂数据仓库,但是简单的Excel就足以胜任高打6万个样本 的数据处理;他虽然不懂专业的展示展现技能,但是只要他自己看的懂就行了,这就无需什么展示展现;前面说过,统计技能是应该掌握的,这对一个人的迷你项目 很重要;他虽然不懂编程,但是专业挖掘工具和挖掘技能足够让他操练的;这样在迷你项目中,一个懂得挖掘技能和市场营销业务能力的人就可以圆满完成了,甚至 在一个数据源中根据业务需求可以无穷无尽的挖掘不同的项目思路,试问就是这个迷你项目,单纯的一个数据仓库专家、单纯的一个程序员、单纯的一个展示展现技 师、甚至单纯的一个挖掘技术专家,都是无法胜任的)。这从另一个方面也说明了为什么沟通能力的重要,这些个完全不同的专业领域,想要有效有机地整合在一起 进行数据挖掘项目实践,你说没有好的沟通能力行吗? 数据挖掘能力只能在项目实践的熔炉中提升、升华,所以跟着项目学挖掘是最有效的捷径。国外学习挖掘的人都是一开始跟着老板做项目,刚开始不懂不要紧, 越不懂越知道应该学什么,才能学得越快越有效果。我不知道国内的数据挖掘学生是怎样学的,但是从网上的一些论坛看,很多都是纸上谈兵,这样很浪费时间,很 没有效率。 另外现在国内关于数据挖掘的概念都很混乱,很多BI只是局限在报表的展示和简单的统计分析,却也号称是数据挖掘;另一方面,国内真正规模化实施数据挖 掘的行业是屈指可数(银行、保险公司、移动通讯),其他行业的应用就只能算是小规模的,比如很多大学都有些相关的挖掘课题、挖掘项目,但都比较分散,而且 都是处于摸索阶段,但是我相信数据挖掘在中国一定是好的前景,因为这是历史发展的必然。 讲到移动方面的实践案例,如果你是来自移动的话,你一定知道国内有家叫华院分析的公司(申明,我跟这家公司没有任何关系,我只是站在数据挖掘者的角度 分析过中国大多数的号称数据挖掘服务公司,觉得华院还不错,比很多徒有虚名的大公司来得更实际),他们的业务现在已经覆盖了绝大多数中国省级移动公司的分 析挖掘项目,你上网搜索一下应该可以找到一些详细的资料吧。我对华院分析印象最深的一点就是2002年这个公司白手起家,自己不懂不要紧,一边自学一边开 始拓展客户,到现在在中国的移动通讯市场全面开花,的确佩服佩服呀。他们最开始都是用EXCEL处理数据,用肉眼比较选择比较不同的模型,你可以想象这其 中的艰难吧。 至于移动通讯的具体的数据挖掘的应用,那太多了,比如不同话费套餐的制订、客户流失模型、不同服务交叉销售模型、不同客户对优惠的弹性分析、客户群体 细分模型、不同客户生命周期模型、渠道选择模型、恶意欺诈预警模型,太多了,记住,从客户的需求出发,从实践中的问题出发,移动中可以发现太多的挖掘项 目。最后告诉你一个秘密,当你数据挖掘能力提升到一定程度时,你会发现无论什么行业,其实数据挖掘的应用有大部分是重合的相似的,这样你会觉得更轻松。 ——专自中国统计网
需求: 用户 与 权限 对应关系为 1:N,需要知道某一个用户对应的所有角色 – SELECT user_id,GROUP_CONCAT(role_id order by role_id asc separator ‘,’) FROM `ipop`.`t_user_role` group by user_id; 此函数可用于关联规则的数据生成,挺实用的。
优化: 1思想的优化想出一种降低业务逻辑的实现方法。 2软件执行效率优化 mysql环境优化: 1.如果order by 没有利用到索引,那么将会出现fileSort,如果sort_buffer不够大,fileSort过程则需要使用临时文件 ,fileSort优化,主要通过调整环境来达到,如下 2.设置参数,优化order by 时可能出现的file sort: 将sort_buffer_size = 1M read_rnd_buffer_size = 1M 修改为sort_buffer_size = 16M read_rnd_buffer_size = 16M 避免order by 过程 进行fileSort排序过程临时文件的产生。从3秒->0.7秒左右 3.去掉distinct,因为distinct加order by,mysql将自动使用临时表 distinct的优化方式详见:http://dev.mysql.com/doc/refman/5.0/en/distinct-optimization.html 4.修改jdbc的url,增加参数useServerPrepStmts=false,使得query cache生效, 这个参数就是让参数与sql连接成整一个字符串,调试对参数中的单引号做了转义,应该 不用担心sql注入攻击了。另外,是否会导致服务端对查询重复的编译而导致的性能下降就不清楚了. explain是用来分析sql语句,帮助优化的一个命令。 explain的语法如下: explain [extended] select … from … where … 如果使用了extended,那么在执行完explain语句后,可以使用show warnings语句查询相应的优化信息。 比如我们执行 select uid from user where uname=’scofield’ order by uid 执行结果会有 Java代码 +—-+————-+——-+——-+——————-+———+———+——-+——+——-+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +—-+————-+——-+——-+——————-+———+———+——-+——+——-+ 这些东西。 id: SELECT的识别符,这是SELECT的查询序列号。 select_type: SELECT类型,有以下几种不同的类型 (1).SIMPLE: 简单的SELECT(不使用UNION或子查询) (2).PRIMARY: 最外面的SELECT,如果我们使用UNION或子查询,第一个查询将会是这个类型 (3).UNION: 使用UNION查询时,除第一个语句外的所有语句会返回这个类型 (4).DEPENDENT UNION: UNION中的第二个或后面的SELECT语句,取决于外面的查询。 (5).UNION RESULT: UNION的结果。 (6).SUBQUERY: 子查询中的第一个SELECT。 (7).DEPENDENT SUBQUERY: 子查询中的第一个SELECT,取决于外面的查询。 (8).DERIVED : 衍生表会返回这个类型。如:select * from (select * from jos_content) as A;。 其中 table 表示是哪个表的数据。 type : 表示表的连接类型,性能由好到差的类型类型为 (System(表中仅有一行,即常量表), const(单表中最多有一个匹配行), eq_ref(对于前面的每一行,在此表中只查询一条记录), ref(使用普通的索引), ref_or_null(和ref类似,但是条件中包含对于NULL查询), index_merge(索引合并优化), unique_subquery(in的后面是一个查询主键字段的子查询), index_subquery(类似unique_subquery,主要是in的后面是查询非唯一索引字段的子查询), range(单表中的范围查询), index(对于当前的每一行,都通过查询索引来得到数据), all(对于当前的每一行,都通过全表扫描来得到数据)) type比较重要。表示链接的类型。链接类型由好到坏的,依次是 system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL一般情况,至少要达到 range 级别,最好是 ref 级别。否则可能会有性能问题。possible_keys 是指可以应用到该表的索引,如果为NULL则没有。key 是指用到的索引。key_len 是索引的长度,在不影响查询精度的情况下,值越小越好 。 ref 是指索引的那一列被使用了。一般会是个常数。 rows MYSQL认为必须检查的用来返回请求数据的行数 。 extra 是指额外的信息。也是比较重要的 。 但这里可以看到的坏的例子是Using temporary和Using filesort,意思MYSQL根本不能使用索引,结果是检索会很慢 (1).Distinct 一旦MYSQL找到了与行相联合匹配的行,就不再搜索了 (2).Not exists MYSQL优化了LEFT JOIN,一旦它找到了匹配LEFT JOIN标准的行, 就不再搜索了 (3).Range checked for each Record(index map:#) 没有找到理想的索引,因此对于从前面表中来的每一个行组合,MYSQL检查使用哪个索引,并用它来从表中返回行。这是使用索引的最慢的连接之一 (4).Using filesort看到这个的时候,查询就需要优化了。MYSQL需要进行额外的步骤来发现如何对返回的行排序。它根据连接类型以及存储排序键值和匹配条件的全部行的行指针来排序全部行 (5).Using index 列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同一个索引的部分的时候 (6).Using temporary看到这个的时候,查询需要优化了。这里,MYSQL需要创建一个临时表来存储结果,这通常发生在对不同的列集进行ORDER BY上,而不是GROUP BY上 (7).Using where 使用了WHERE从句来限制哪些行将与下一张表匹配或者是返回给用户。如果不想返回表中的全部行,并且连接类型ALL或index,这就会发生,或者是查询有问题 如果为 where used 说明使用了where语句。如果 type为 all 或者 index ,一般会出现这样的结果。这样的问题,一般是查询需要改进。 在一般稍大的系统中,基本尽可能的减少join ,子查询等等。mysql就使用最简单的查询,这样效率最高。至于 join 等,可以放在应用层去解决。 3. 使用EXPLAIN分析低效SQL的执行计划。 在查询到效率低的SQL语句后,那我们可以使用explain或者DESC命令获取Myswl如何执行SELECT语句的信息,包括在Select语句执行过程中表如何连接和连接的顺序。 例如你想计数xxxx年公司的销售额,那么需要操作sales和comapny table,并对money字段进行sum操作。看看怎么使用explain: Java代码 explain select sum(moneys) from sales a company b where a.company_id = b.id and a.year=XXXX \G;(注意加上\G是为了更好的看)
最近在用Vertica的时候碰到一个问题,Vertica在运行了一段时间后总是出现类似下面的错误 1 2 java.sql.SQLException: [Vertica][VJDBC](5065) ERROR: Too many ROS containers existforthe following projections: <projection> (limit =18078, ROS files =12088, DV files =5992,newfiles =10) 碰到找个问题就不得不说说Vertica的存储机制了。Vertica在默认情况下会把新写入的数据写入到WOS(写优化)中,然后根据一定的条件(比如说一定的时间周期)再把WOS中的数据写入到ROS(读优化)中,这时ROS有可能很多都是很小数据块的碎片,这是Vertica会在一定的时间周期后把这些ROS数据块合并成大的ROS文件。 这里把数据从WOS写入到ROS的过程Vertica管它叫MoveOut操作,而把零散的ROS合并成大的ROS的过程Vertica管它叫MergeOut操作。 好了,现在来看看我们的问题吧。错误里报的是ROS太多,那可能的原因是 1. WOS写ROS太多,这个原因的原因很大的可能是每次insert/update的数据集太小,导致生成的碎片太多。 2. ROS太多,而配置的MoveOut和MergeOut的时间间隔太长,导致来不及做MoveOut和MergeOut。 好吧来看看我的应用吧 1. 针对第一个可能的原因,确实是我们的应用的需求的问题,这个目前来说我们没法改变。 2. 对于第二个可能的原因,我们查了一下Vertica的资料,在Vertica中默认的MergeOutInterval是600,MoveOutInterval是300。这两个参数可以通过下面的命令来查看 1 2 SELECTGET_CONFIG_PARAMETER(‘MoveOutInterval’); SELECTGET_CONFIG_PARAMETER(‘MergeOutInterval’); 由于我们的应用本身会产生很多的ROS碎片,所以我们想到了是不是可以通过减小MoveOut和MergeOut的Interval来让Vertica尽快的做MoveOut和MergeOut。因此我们修改了Vertica的参数 1 2 SELECTSET_CONFIG_PARAMETER(‘MoveOutInterval’, 60); SELECTSET_CONFIG_PARAMETER(‘MergeOutInterval’, 30); 在修改了这两个参数以后,我们的应用确实在运行了很长时间后都没有再出现上面的问题了。 其实关于这个问题,还有几个参数可以调节,具体资料可以参考Vertica Tuple Mover Parameters
会员的价值体现在持续不断的为企业带来稳定的销售和利润,同时也为企业策略的制定提供数据支持。所以零售企业总是想尽一切办法去吸引更多的人成为会员,并且尽可能提高他们的忠诚度。忠诚度高的顾客表现为经常光顾购买,有较高的价格忍耐度,愿意支付更高的价格,也愿意向其他人推荐,对品牌满意度较高等。会员忠诚度高不一定会员价值就高,还得看他的实际消费金额,也就是消费力。忠诚度高、消费力强的顾客才是企业最优质的会员顾客。由于会员价值中“愿意向他人推荐”这个项目不好采集数据来量化,满意度也需要专项调查才能取得数据。所以结合这些特点,我们可以从以下几个指标去评估会员的综合价值: 1、最近一次消费时间理论上来讲,上一次购买时间距离现在越近的顾客价值越大。而他们得到营销人员眷顾的机会也应该大于那些很久没有光顾的顾客。当一位已经半年没有光临的顾客上周再次产生购买,那他就激活了自己的这个指标,所以最近一次消费时间是实时变化的,所以我们需要不断的激活顾客消费。 2、(某个周期内的)消费频率消费频率越高的顾客忠诚度越大,我们需要不断的采取营销手段去提高每个顾客的消费频率,这也是提高销售额非常有效的方法。一个产品没有重复购买的企业是非常危险的,意味着他的顾客都是新的,都是一锤子买卖。不光传统零售,现在重复购买率也是衡量一个电商网站的关键指标。消费频率最高的这部分顾客应该是得到企业关爱最多的群体,需要注意的是数据库营销不能过度营销,要以不骚扰用户为原则。 3、(某个周期内的)消费金额消费金额越大,顾客消费力也越大,在二八法则中,20%的顾客贡献了80%的销售额,而这些顾客也应该是得到营销资源最多的顾客。特别是当你的促销活动的费用资源不足的时候,这些高端的顾客就是你的首选对象。这个指标还需要和消费频率结合起来分析,有的顾客消费金额非常高,但是他可能只是购买了一次高单价商品,就再也没有光临过了。 这三项指标是著名的顾客价值研究的RFM模型,分别是R-Recency(最近购买时间),F-Frequency(消费频率),M-Monetary(消费金额)。这三个指标来自于美国数据库营销机构的研究,现在逐渐成为会员价值研究以及会员营销的通用模型了。 这里的RFM模型和进而细分客户仅是数据挖掘项目的一个小部分,假定我们拿到一个月的客户消费行为数据集(实际上有六个月的数据),我们们先用IBM Modeler软件构建一个分析流: 我们先用挖掘工具的RFM模型的RFM汇总节点和RFM分析节点产生R(Recency)、F(Frequency)、M (Monetary); 接着我们采用RFM分析节点就完成了RFM模型基础数据重构和整理; 现在我们得到了RFM模型的Recency_Score、Frequency_Score、Monetary_Score和RFM_Score;这里对RFM得分进行了五等分切割,采用100、10、1加权得到RFM得分表明了125个RFM魔方块。 传统的RFM模型到此也就完成了,但125个细分市场太多啦无法针对性营销也需要识别客户特征和行为,有必要进一步细分客户群; 另外:RFM模型其实仅仅是一种数据处理方法,采用数据重构技术同样可以完成,只是这里固化了RFM模块更简单直接,但我们可以采用RFM构建数据的方式不为RFM也可用该模块进行数据重构。 接下来,我们继续采用挖掘工具对R、F、M三个字段进行聚类分析,聚类分析主要采用:Kohonen、K-means和Two-step算法。 这时候我们要考虑是直接用R(Recency)、F(Frequency)、M (Monetary)三个变量还是要进行变换,因为R、F、M三个字段的测量尺度不同最好对三个变量进行标准化,例如:Z得分(实际情况可以选择线性插值法,比较法,对标法等标准化)!另外一个考虑:就是R、F、M三个指标的权重该如何考虑,在现实营销中这三个指标重要性显然不同! 有资料研究表明:对RFM各变量的指标权重问题,Hughes,Arthur认为RFM在衡量一个问题上的权重是一致的,因而并没有给予不同的划分。而Stone,Bob通过对信用卡的实证分析,认为各个指标的权重并不相同,应该给予频度最高,近度次之,值度最低的权重; 这里我们采用加权方法:WR=2 WF=3 WM=5的简单加权法(实际情况需要专家或营销人员测定);具体选择哪种聚类方法和聚类数需要反复测试和评估,同时也要比较三种方法哪种方式更理想! 下图是采用快速聚类的结果: 以及kohonen神经算法的聚类结果: 接下来我们要识别聚类结果的意义和类分析,这里我们可以采用C5.0规则来识别不同聚类的特征,采用评估分析节点对C5.0规则的模型识别能力进行判断: 结果还不错,我们可以分别选择三种聚类方法,或者选择一种更易解释的聚类结果,这里选择Kohonen的聚类结果将聚类字段写入数据集后,为方便我们将数据导入SPSS软件进行均值分析和输出到Excel软件! 输出结果后将数据导入Excel,将R、F、M三个字段分类与该字段的均值进行比较,利用Excel软件的条件格式给出与均值比较的趋势!结合RFM模型魔方块的分类识别客户类型:通过RFM分析将客户群体划分成重要保持客户、重要发展客户、重要挽留客户、一般重要客户、一般客户、无价值客户等六个级别;(有可能某个级别不存在); 另外一个考虑是针对R、F、M三个指标的标准化得分按聚类结果进行加权计算,然后进行综合得分排名,识别各个类别的客户价值水平; 至此如果我们通过对RFM模型分析和进行的客户细分满意的话,可能分析就此结束!如果我们还有客户背景资料信息库,可以将聚类结果和RFM得分作为自变量进行其他数据挖掘建模工作!
本文地址:http://blog.csdn.net/kongxx/article/details/7176961 最近在对Vertica做压力测试的时候,发现当并发请求数达到50+的时候就会出现下面的异常 [plain] view plaincopyprint? com.vertica.util.PSQLException: FATAL: New session rejected due to limit, already 55 sessions active at com.vertica.core.v3.ConnectionFactoryImpl.readStartupMessages(Unknown Source) at com.vertica.core.v3.ConnectionFactoryImpl.openConnectionImpl(Unknown Source) at com.vertica.core.ConnectionFactory.openConnection(Unknown Source) at com.vertica.jdbc2.AbstractJdbc2Connection.<init>(Unknown Source) at com.vertica.jdbc3.AbstractJdbc3Connection.<init>(Unknown Source) at com.vertica.jdbc3g.Jdbc3gConnection.<init>(Unknown Source) at com.vertica.Driver.makeConnection(Unknown Source) at com.vertica.Driver.connect(Unknown Source) at org.apache.commons.dbcp.DriverConnectionFactory.createConnection(DriverConnectionFactory.java:38) at org.apache.commons.dbcp.PoolableConnectionFactory.makeObject(PoolableConnectionFactory.java:582) at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:1181) at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:106) at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044) at DBUtil.getConnection(DBUtil.java:64) at DBQueryPerformanceTest.query(DBQueryPerformanceTest.java:46) at DBQueryPerformanceTest.access$000(DBQueryPerformanceTest.java:14) at DBQueryPerformanceTest$1.execute(DBQueryPerformanceTest.java:40) at DBPerformanceTest.runIt(DBPerformanceTest.java:97) at DBPerformanceTest$1.run(DBPerformanceTest.java:51) at java.lang.Thread.run(Thread.java:619) com.vertica.util.PSQLException: The connection attempt failed. at com.vertica.core.v3.ConnectionFactoryImpl.openConnectionImpl(Unknown Source) at com.vertica.core.ConnectionFactory.openConnection(Unknown Source) at com.vertica.jdbc2.AbstractJdbc2Connection.<init>(Unknown Source) at com.vertica.jdbc3.AbstractJdbc3Connection.<init>(Unknown Source) at com.vertica.jdbc3g.Jdbc3gConnection.<init>(Unknown Source) at com.vertica.Driver.makeConnection(Unknown Source) at com.vertica.Driver.connect(Unknown Source) at org.apache.commons.dbcp.DriverConnectionFactory.createConnection(DriverConnectionFactory.java:38) at org.apache.commons.dbcp.PoolableConnectionFactory.makeObject(PoolableConnectionFactory.java:582) at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:1181) at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:106) at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044) at DBUtil.getConnection(DBUtil.java:64) at DBQueryPerformanceTest.query(DBQueryPerformanceTest.java:46) at DBQueryPerformanceTest.access$000(DBQueryPerformanceTest.java:14) at DBQueryPerformanceTest$1.execute(DBQueryPerformanceTest.java:40) at DBPerformanceTest.runIt(DBPerformanceTest.java:97) at DBPerformanceTest$1.run(DBPerformanceTest.java:51) at java.lang.Thread.run(Thread.java:619) Caused by: java.net.SocketException: Connection reset at java.net.SocketInputStream.read(SocketInputStream.java:168) at java.io.BufferedInputStream.fill(BufferedInputStream.java:218) at java.io.BufferedInputStream.read(BufferedInputStream.java:237) at com.vertica.core.PGStream.ReceiveChar(Unknown Source) at com.vertica.core.v3.ConnectionFactoryImpl.doAuthentication(Unknown Source) … 19 more 出现这个问题是由于Vertica中指定了MaxClientSessions参数,此时可以通过下面的SQL来修改此值 [sql] view plaincopyprint? <pre name=“code” class=“sql”>SELECT SET_CONFIG_PARAMETER (‘MaxClientSessions’, 250);</pre><br> <br> <pre></pre> <p></p> <pre></pre> <br> <br> <p></p> <p><br> </p> <p><br> </p>