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

记一次wordpress性能优化

$
0
0


wordpress真的很流行,但是我真的不认为它的性能好,尤其当数据超过几万十几万的时候。当然作为一个个人博客来说超过几万的数据是一件很难的事情。可我现在用wordpress作为CMS使用,数据库中有十几万条数据。

新租的云主机配置为:2核2GHZ的CPU、1G内存、CentOS6.4操作系统。安装完Apache、php、MySQL后导入数据打开首页一看,竟然用了十几秒的时间才打开首页。经过研究发现主要是php生成页面很慢,猜测可能是数据库查询比较慢,另外页面加载也有需要优化的地方。因此我做了一系列的优化,主要集中在以下几点:

1.数据库参数调整。

2.启用数据库查询缓存。

3.增加索引以提高查询效率。

4.使用eaccelerator提高php执行速度。

5.优化文件加载。


第一步:调整MySQL参数。

调整参数我是参考my-medium.cnf文件进行的,该文件中有详细的说明,在此不再详细说明。


第二步:打开MySQL的通用查询日志和慢查询日志。

打开方法在MySQL配置文件中加入如下两条配置项并重启MySQL服务使其生效。

log=/var/log/mysql/log.log
long-query-time=0.02
slow_query_log=/var/log/mysql/slow.log

刷新几次页面并分别观察两个日志。

通过观察通用查询日志发现每个页面生成都要有很多次数据库查询,其中大部分是不需要每次打开一个页面就需要查询的,如从wp_options表中获取option。所以需要开启MySQL的查询缓存,方法为在MySQL配置文件中加入如下配置项:

query-cache-type=1 # 0:不启用查询缓存;1:默认缓存,除非在SELECT语句中指定SQL_NO_CACHE;2:默认不缓存,除非在SELECT中指定SQL_CACHE;
query_cache_limit=3M # 缓存的最大单个查询结果集。
query_cache_size=64M # 查询缓存可用的最大内存。
query_cache_min_res_unit=0k # 缓存的最小查询结果集。
query_cache_wlock_invalidate=0 # 1:写锁定发生在表上时该表的查询缓存立即失效; 0:写锁定发生在表上时写锁定期间查询缓存仍然有效。

重启生效后刷新几次页面以及打开其他页面,页面的整个加载时间在两秒左右,其中页面生成时间在一秒以上,相比之前来说可以说是立竿见影。

query_cache_size参数其实并不需要这么大,对于wordpress来说我只是想缓存一些结果集不易变的细碎查询,对于文章详细页和文章列表页做缓存实在是不现实,所以此处16M足矣(当时我给的太大了)。

不必要的WHERE条件


第三步:增加索引

根据查询WHERE条件中的字段添加索引。


第四步:提高PHP执行效率。

众所周知,PHP的执行效率相对来说还是比较低的,wordpress又是一个比较复杂的博客系统,性能一直马马虎虎。我们自己动手优化wordpress代码不怎么现实,所以我想到了用eaccelerator来提高PHP执行效率。eaccelerator的官方网址为 https://github.com/eaccelerator/eaccelerator/。其官方简介如下

eAccelerator is a free open source PHP accelerator and optimizer for PHP. It increases the performance of PHP scripts by caching them in compiled state, so the overhead of compiling  is  almost completely eliminated. It also optimizes the scripts to speed up execution. eAccelerator typically reduces server load and increases the speed of your PHP code by 1-10 times.

官方文档中有详细的安装和配置方法,请参考官方文档那个进行。

安装完成后又刷新了一下页面,生成页面的速度降低到两三百个毫秒。

两三百个还秒对于当前使用的主机我已经很满意了。


第五步:页面加载也要做一些优化,css和js该合并的合并,该压缩的压缩。图片该合并的合并,不必要的资源停止加载。对于现代浏览器支持的manifest缓存也适当的应用上了,将图片、css、js等静态资源直接缓存到客户端。


后记:

我也找了一些wordpress优化插件,如WP Super Cache等,虽然有一定的效果,但是依然没有痛快的感觉。

另外对于所有的php+MySQL应用来说这些经验都是可以借鉴的。




作者:tt361 发表于2014-5-2 9:54:49 原文链接
阅读:2 评论:0 查看评论

Spring AOP注解通过@Autowired,@Resource,@Qualifier,@PostConstruct,@PreDestroy注入属性的配置文件详解

$
0
0

原创整理不易,转载请注明出处: Spring AOP注解通过@Autowired,@Resource,@Qualifier,@PostConstruct,@PreDestroy注入属性的配置文件详解

代码下载地址: http://www.zuidaima.com/share/1772661373422592.htm

本文介绍了使用Spring注解注入属性的方法。使用注解以前,注入属性通过类以及配置文件来实现。现在,注入属性可以通过引入@Autowired注解,或者@Resource,@Qualifier,@PostConstruct,@PreDestroy等注解来实现。

1.1. 使用注解以前我们是怎样注入属性的

类的实现:

public class UserManagerImpl implements UserManager {     
    private UserDao userDao;     
    public void setUserDao(UserDao userDao) {     
        this.userDao = userDao;     
    }     
    ...     
} 

配置文件:

<bean id="userManagerImpl" class="com.kedacom.spring.annotation.service.UserManagerImpl"> <property name="userDao" ref="userDao" /> </bean> <bean id="userDao" class="com.kedacom.spring.annotation.persistence.UserDaoImpl"> <property name="sessionFactory" ref="mySessionFactory" /> </bean>   

1.2. 引入@Autowired注解(不推荐使用,建议使用@Resource)

类的实现(对成员变量进行标注)

public class UserManagerImpl implements UserManager {  
    @Autowired 
    private UserDao userDao;  
    ...  
}  

或者(对方法进行标注)

public class UserManagerImpl implements UserManager {  
    private UserDao userDao;  
    @Autowired 
    public void setUserDao(UserDao userDao) {  
        this.userDao = userDao;  
    }  
    ...  
} 

配置文件

<bean id="userManagerImpl" class="com.kedacom.spring.annotation.service.UserManagerImpl" /> <bean id="userDao" class="com.kedacom.spring.annotation.persistence.UserDaoImpl"> <property name="sessionFactory" ref="mySessionFactory" /> </bean> 

@Autowired可以对成员变量、方法和构造函数进行标注,来完成自动装配的工作。以上两种不同实现方式中,@Autowired的标注位置不同,它们都会在Spring在初始化userManagerImpl这个bean时,自动装配userDao这个属性,区别是:第一种实现中,Spring会直接将UserDao类型的唯一一个bean赋值给userDao这个成员变量;第二种实现中,Spring会调用 setUserDao方法来将UserDao类型的唯一一个bean装配到userDao这个属性。

1.3. 让@Autowired工作起来

要使@Autowired能够工作,还需要在配置文件中加入以下代码

<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />   

1.4. @Qualifier

@Autowired是根据类型进行自动装配的。在上面的例子中,如果当Spring上下文中存在不止一个UserDao类型的bean时,就会抛出BeanCreationException异常;如果Spring上下文中不存在UserDao类型的bean,也会抛出 BeanCreationException异常。我们可以使用@Qualifier配合@Autowired来解决这些问题。

a. 可能存在多个UserDao实例

@Autowired 
public void setUserDao(@Qualifier("userDao") UserDao userDao) {  
    this.userDao = userDao;  
}  

这样,Spring会找到id为userDao的bean进行装配。

b. 可能不存在UserDao实例

@Autowired(required = false)  
public void setUserDao(UserDao userDao) {  
    this.userDao = userDao;  
}   

1.5. @Resource(JSR-250标准注解,推荐使用它来代替Spring专有的@Autowired注解)

Spring 不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解,它们分别是@Resource、@PostConstruct以及@PreDestroy。

@Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按 byName自动注入罢了。@Resource有两个属性是比较重要的,分别是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。

@Resource装配顺序
1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配(见2);如果没有匹配,则回退为一个原始类型(UserDao)进行匹配,如果匹配则自动装配;

1.6. @PostConstruct(JSR-250)

在方法上加上注解@PostConstruct,这个方法就会在Bean初始化之后被Spring容器执行(注:Bean初始化包括,实例化Bean,并装配Bean的属性(依赖注入))。

它的一个典型的应用场景是,当你需要往Bean里注入一个其父类中定义的属性,而你又无法复写父类的属性或属性的setter方法时,如:

public class UserDaoImpl extends HibernateDaoSupport implements UserDao {  
    private SessionFactory mySessionFacotry;  
    @Resource 
    public void setMySessionFacotry(SessionFactory sessionFacotry) {  
        this.mySessionFacotry = sessionFacotry;  
    }  
    @PostConstruct 
    public void injectSessionFactory() {  
        super.setSessionFactory(mySessionFacotry);  
    }  
    ...  
}   

这里通过@PostConstruct,为UserDaoImpl的父类里定义的一个sessionFactory私有属性,注入了我们自己定义的sessionFactory(父类的setSessionFactory方法为final,不可复写),之后我们就可以通过调用 super.getSessionFactory()来访问该属性了。

1.7. @PreDestroy(JSR-250)

在方法上加上注解@PreDestroy,这个方法就会在Bean初始化之后被Spring容器执行。由于我们当前还没有需要用到它的场景,这里不不去演示。其用法同@PostConstruct。

1.8. 使用< context:annotation-config />简化配置

Spring2.1添加了一个新的context的Schema命名空间,该命名空间对注释驱动、属性文件引入、加载期织入等功能提供了便捷的配置。我们知道注释本身是不会做任何事情的,它仅提供元数据信息。要使元数据信息真正起作用,必须让负责处理这些元数据的处理器工作起来。

AutowiredAnnotationBeanPostProcessor和 CommonAnnotationBeanPostProcessor就是处理这些注释元数据的处理器。但是直接在Spring配置文件中定义这些 Bean显得比较笨拙。Spring为我们提供了一种方便的注册这些BeanPostProcessor的方式,这就是< context:annotation-config />:

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans  
    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
    http://www.springframework.org/schema/context  
    http://www.springframework.org/schema/context/spring-context-2.5.xsd"> < context:annotation-config /> </beans>   

<context:annotationconfig />将隐式地向Spring容器注册AutowiredAnnotationBeanPostProcessor、 CommonAnnotationBeanPostProcessor、 PersistenceAnnotationBeanPostProcessor以及 RequiredAnnotationBeanPostProcessor这4个BeanPostProcessor。

作者:yaerfeng 发表于2014-5-2 9:38:31 原文链接
阅读:0 评论:0 查看评论

跟踪OpenLDAP服务器性能

$
0
0

原文: http://prefetch.net/articles/monitoringldap.html

 

LDAP已经成为互联网标准的目录访问协议,并且用于访问一切从DNS区域文件到用户帐户信息。随着企业和软件供应商更多地依赖于LDAP目录服务器,需要测量服务器的吞吐量和性能变得势在必行。本文将介绍可用于监视LDAP目录服务器的运行状况和性能优化的工具,并且将解释随着时间的推移ORCA如何越来越多地应用到目录服务器的性能监测中。

日志


在诊断一个LDAP服务器性能的时候,一开始通常是查看日志文件。 OpenLDAP服务器提供了一个灵活的日志子系统,并定义了几种日志级别来控制日志文件的详细程度:

 级别  描述

-1    启动所有调试

0     不输出调试

1     跟踪功能调用

2     调试数据包处理

4     深度跟踪调试

8     连接管理

16    打印数据包发送和接收

32    查询过滤器处理

64    配置文件处理

128   访问控制列表处理

256   统计日志连接/操作/结果

512   发送统计日志条目

1024  打印与shell后端的通信

2048  打印条目解析调试

 每个日志级别都可以附加,并且可以通过slapd.conf的“loglevel”指令进行配置,或者作为参数“-d”选项传递给slapd。下面的示例演示如何记录访问控制列表和搜索过滤器处理的详细信息:

 $ slapd -4 -f /etc/slapd.conf -u openldap -g openldap \

  -h "ldap://ldap.prefetch.net  ldaps://ldap.prefetch.net" -d 160

 OpenLDAP将默认记录所有信息到syslog的LOCAL4设备。如果你想使用一个不同的设备,你可以通过slapd的“-l”选项配置设备名。

跟踪操作时间


当LDAP客户机和服务器通过路由器和防火墙分隔时,偶尔发生的网络问题(例如,丢失的TCP段或损坏的CRC)可能会导致应用程序意外的行为。为了帮助衡量一个LDAP客户机和服务器之间的延迟,我们开发了 ldap-ping.pl。ldap-ping.pl是用Perl编写的,并且依赖于Time::HiRes, Getopt::Std, Net::LDAP 和Net::LDAPS模块。

ldap-ping.pl的工作原理是打开一个TCP连接到目录服务器,发出匿名绑定,搜索RootDSE,并从服务器取消绑定。这些操作使用Perl的高分辨率计时器进行测量,并以“ping”的格式进行显示:

 $ ldap-ping.pl -s ldap.prefetch.net -p 389 -d 10

Querying LDAP server ldap.prefetch.net:389 every 10 seconds (Ctrl-C to stop):
Fri Nov 12 16:42:14 2004: new=0.025s, = bind=0.008s, search=0.067s, unbind=0.003s [local port=50377] [Normal Delay]
Fri Nov 12 16:42:25 2004: new=0.011s, = bind=0.001s, search=0.015s, unbind=0.001s [local port=50378] [Normal Delay]
Fri Nov 12 16:42:35 2004: new=0.010s, = bind=0.002s, search=0.015s, unbind=0.001s [local port=50379] [Normal Delay]
Fri Nov 12 16:42:45 2004: new=0.009s, = bind=0.002s, search=0.015s, unbind=0.001s [local port=50380] [Normal Delay]

 ldap-ping.pl脚本接受三个参数; “-s”选项表示连接到的服务器,“-p”选项指定目录服务器监听的TCP端口,而“-d”选项允许管理员指定探测之间的延迟。如果存在二进制pfiles文件,脚本也将打印本地端口号。

跟踪性能


OpenLDAP服务器可以被配置为通过monitor branch的指令提供实时的性能统计数据。目前可用的统计信息包括:发送的字节数,返回到客户机的条目,连接到服务器的总数,当前活动的连接,读写等待者,和个别的操作(例如,读取、搜索、修改)故障。下面的例子展示了slapd.conf中设置monitor branch的指令,并限制读取访问的IP地址为192.168.1.8:

 database                   monitor

 
access to dn="cn=monitor"
        by peername=192.168.1.8   read
        by * none

 一旦配置了monitor branch,我们可以使用“ldapsearch”工具查看所有可用的统计数据:

 $ ldapsearch -x -b "cn=monitor"-H ldaps://ldap.prefetch.net objectclass=*

 我们可以也通过调整search base 获取个别统计信息:

 $ ldapsearch -LLL -x -b "cn=Current,cn=Connections,cn=Monitor" -H ldaps://ldap.prefetch.net objectclass=*

dn: cn=Current,cn=Connections,cn=Monitor
objectClass: top
objectClass: monitor
objectClass: extensibleObject
cn: Current
description: 46
 

收集性能数据


使用ldapsearch实用程序可以让我们收集到某个时间点的性能指标快照,但是我们怎样才能利用历史数据呢?为了解决这个问题,我开发了 ldap-gather.pl。ldap-gather.pl脚本从monitor branch收集统计信息,并将其写入到传递的目录参数中:

 $ ldap-gather.pl -s ldap.prefetch.net -p 389 -d /usr/local/orca/var/orca/ldapallator/ldap.prefetch.net:389

 初始调用ldap-gather.pl将产生一个文本文件,包含一行描述数据头,及一行实际数据:

 TIMESTAMP TOTAL_CONNECTIONS BYTES_SENT COMPLETED_OPERATIONS REFERRALS_SENT ENTRIES_SENT BIND_OPERATIONS UNBIND_OPERATIONS ADD_OPERATIONS DELETE_OPERATIONS MODIFY_OPERATIONS COMPARE_OPERATIONS SEARCH_OPERATIONS

1100656501 118 649271 165 0 4620 24 24 0 0 0 0 117

 如果数据文件不存在,ldap-gather.pl脚本将创建一个新的数据文件,如果该文件存在,将追加新的数据。该文件名包含单词“ldapallator”和一个日期戳(例如,filename -YYYY-MO-DD-INDEX):

 $ ls -la | tail -1

-rw-r--r--   1 orca     other       6424 Nov 29 17:25 ldapallator-2004-10-29-000

 若要自动在相同的时间间隔采集数据,我们可以设置一个cron作业运行ldap -gather.pl:

 5,15,25,35,45,55 * * * * sh -c "/usr/local/etc/ldap-gather.pl

                            -s ldap.prefetch.net 
                            -p 389 -d /usr/local/orca/var/orca/ldapallator/ldap.prefetch.net:389"

 这将使ldap-gather.pl每十分钟收集一次性能数据。一旦数据被捕获,我们可以使用ORCA来生成图表性能报告。

把LDAP性能数据生成图表


该ORCA包中包含了一组Perl脚本和配置文件来绘制任意数据。 ORCA使用RRD存储数据,并配置了一个配置文件。 ORCA采用了典型的“configure”,“make”和“make install”步骤构建软件包。 ORCA的Perl脚本使用Data::Dumper、Digest::MD5、Math::IntervalSearch、 RRD和Storable模块,使用“makemodules_install”选项与现有的Perl安装整合。一旦安装完成,可以执行“orca”,以确保成功地完成了构建过程:

 $ /usr/local/orca/bin/orca

/usr/local/orca/bin/orca: no configuration file specified
usage: /usr/local/orca/bin/orca [options] configuration_file
Options:
  -daemon           Run Orca in daemon mode
  -gifs             Output GIFs instead of PNGs
  -logfile filename Output all messages
  -no-html          Update RRD files and images but not HTML files
  -no-images        Update RRD files but not image and HTML files
  -once             Run only once and do not continue to monitor input files
  -verbose          Verbose; list multiple times for increased verbosity
Orca understands the first unique command line option, i.e. -d for -daemon.

 如果Perl解释器无法找到所需的模块之一,你会看到各种各样的控制台上的错误,并且进程将退出。一旦Perl解释器执行正常,我们可以创建一个ORCA配置文件,并开始收集ldap-gather.pl的数据以便进一步分析。

ORCA配置文件包含需要找到和生成图形数据的指令。该配置文件包含三个主要部分,第一部分定义了几个变量(例如,base_dir,rrd_dir,html_dir),用于控制RRD和图像文件的存储位置。本节还包含几个变量来定义ORCA生成的网页格式。

第二部分包含了一系列的“group”条目,它定义了生成图表的数据。匹配由ldap-gather.pl收集到的文件的样本组条目如下图所示:

 group ldapallator {

find_files              /usr/local/orca/var/orca/ldapallator/(.*)/(?:ldapallator)-\d{4}-\d{2}-\d{2}(?:-\d{3,})?(?:\.(?:Z|gz
|bz2))?
column_description      first_line
date_source             column_name TIMESTAMP
interval                600
filename_compare        sub {
                          my ($ay, $am, $ad) = $a =~ /-(\d{4})-(\d\d)-(\d\d)/;
                          my ($by, $bm, $bd) = $b =~ /-(\d{4})-(\d\d)-(\d\d)/;
                          if (my $c = (( $ay       <=>  $by) ||
                                       ( $am       <=>  $bm) ||
                                       (($ad >> 3) <=> ($bd >> 3)))) {
                            return 2*$c;
                          }
                          $ad <=> $bd;
                        }
}

 在这个例子中,“find_files”关键字告诉ORCA什么文件作为输入使用(该文件与一个正则表达式匹配)。“interval”关键字定义的秒数表示在这组数据文件更新之间的间隔时间,而“column_description”描述的是列描述的位置。“column_description”值“first_line”表示该栏位说明将位于每个文件的第一行。

第三部分包含了一组plot表示图表的各条目。下面的例子显示了需要​​绘制目录服务器的连接数的指令:

 plot {

title                   %g Total Connections
source                  ldapallator
data                    TOTAL_CONNECTIONS
data_type               derive
line_type               line2
legend                  Connections
y_legend                Connections
data_min                0
}

  “plot”关键字定义一个新的图,其中包含指定的标题“title”,“source”关键字表示此图来源的“group”条目。每个图形使用“data”关键字按名称来引用数据的特定列(例如,TOTAL_CONNECTIONS是ldap-gather.pl收集的每个数据文件的列);“data_type”关键字指定数据是否会被绘制为绝对值,以前的值的衍生物,或一个计数器。曲线图的X轴的值可以用“data_min”和 “data_max”控制;最后在ORCA创建的PNG文件中可读的图例描述。

可以调用ORCA来一次性处理数据并退出,或设置以一个守护进程运行,不断检查是否有新的数据。下面的示例运行ORCA一次性处理自上次调用以来所有的数据:

 $ /bin/sh -c "cd /usr/local/orca &&/usr/local/orca/bin/orca -once /usr/local/orca/lib/ldapallator.cfg"

 如果ORCA成功运行,会在“html_dir”目录中生成HTML和PNG文件。如果您不想以守护进程运行ORCA,你需要添加一个cron作业以便在相同的时间间隔内循环来处理的文件:

 0 0 * * * /bin/sh -c "cd /usr/local/orca &&/usr/local/orca/bin/orca -once

         /usr/local/orca/lib/ldapallator.cfg" > /dev/null 2>&1

 该命令执行将在半夜运行ORCA的日常作业,并处理前一天的数据。 图3包含了一个完整的ORCA配置文件,图4,图5和6包含ORCA的连接总数、总运行数和返回的条目数的图表。

图4连接总数


图5 运行总数


图6 返回的条目数

结论


本文提供的几种监视LDAP服务器技术的概述。在我们的例子中我们用的是OpenLDAP服务器,但这些技术也适用于商业目录服务器。有关ORCA的其他信息,它可以被用来绘制任意数据,以及其它的方面,请参见参考资料。如果您对本文章存在疑问或意见,请随时给作者发 E-mail

参考


这篇文章参考了下面的内容:

致谢


感谢克莱麦克卢尔的ldap-ping.pl原创作品,还要感谢ORCA和OpenLDAP团队成员的卓越贡献!

作者:wilbertzhou 发表于2014-5-2 18:18:22 原文链接
阅读:77 评论:0 查看评论

JBPM学习(一):实现一个简单的工作流例子全过程

$
0
0

test.png



test.jpdl.xml

<?xml version="1.0" encoding="UTF-8"?><process name="test" xmlns="http://jbpm.org/4.4/jpdl"><start g="247,9,48,48" name="start1"><transition g="-69,-22" name="to 员工提交申请" to="员工提交申请"/></start><end g="244,326,48,48" name="end1"/><task assignee="员工" g="223,84,92,52" name="员工提交申请"><transition g="-93,-22" name="to 部门经理审批" to="部门经理审批"/></task><task assignee="部门经理" g="226,161,92,52" name="部门经理审批"><transition g="-81,-22" name="to 总经理审批" to="总经理审批"/></task><task assignee="总经理" g="222,244,92,52" name="总经理审批"><transition g="-50,-22" name="to end1" to="end1"/></task></process>

Task

assignee

员工提交申请

员工

部门经理审批

部门经理

总经理审批

总经理

1.部署流程定义

a) 通过直接拿到.jpdl.xml和.png方式部署

@Test
	public void deployProcessDefinition() {
		processEngine.getRepositoryService()//
				.createDeployment()//
				.addResourceFromClasspath("test.jpdl.xml")//
				.addResourceFromClasspath("test.png")//
				.deploy();
	}

b) 部署完后,在jbpm4_ployment表中有一条记录;在jbpm4_lob表有两条记录,分别为test.jpdl.xml和test.png。

2.启动流程实例

a) 通过key启动流程实例,.jpdl.xml中key不写默认为name属性

@Test
	public void startProcessInstance() {
		processEngine.getExecutionService().startProcessInstanceByKey("test");
	}

b) 启动流程实例后:jbpm4_execution表中有一条员工提交申请的活动记录,此时进行到 to员工提交申请环节。

3.员工操作

a) 查询未办理的任务列表

@Test
	public void findMyTaskList() {
		// 查询任务
		String userId = "员工";
		List<Task> list = processEngine.getTaskService().findPersonalTasks(userId);

		// 显示任务
		System.out.println("========= 【"+userId+"】的未办理的任务列表 =========");
		for (Task task : list) {
			System.out.println("id=" + task.getId()//
					+ ", name=" + task.getName()//
					+ ", assignee=" + task.getAssignee()//
					+ ", createTime=" + task.getCreateTime());
		}
	}

b) 查看到信息如下:有一条任务id为20002

========== 【员工】的未办理的任务列表 =========

id=20002, name=员工提交申请, assignee=员工, createTime=2014-05-02 16:48:04.0

c) 员工办理任务:提交申请环节

@Test
	public void completeTask() {
		String taskId = "20002";
		processEngine.getTaskService().completeTask(taskId);
	}

d) 员工执行完任务,即 员工提交申请环节结束,环节进行到 to部门经理审批,此时员工再查询个人任务列表结果为空。

4.部门经理操作

a) 查询未办理的任务列表

@Test
	public void findMyTaskList() {
		// 查询任务
		String userId = "部门经理";
		List<Task> list = processEngine.getTaskService().findPersonalTasks(userId);

		// 显示任务
		System.out.println("========= 【"+userId+"】的未办理的任务列表 =========");
		for (Task task : list) {
			System.out.println("id=" + task.getId()//
					+ ", name=" + task.getName()//
					+ ", assignee=" + task.getAssignee()//
					+ ", createTime=" + task.getCreateTime());
		}
	}

b) 查看到信息如下:有一条任务id为30001

========== 【部门经理】的未办理的任务列表 =========

id=30001, name=部门经理审批, assignee=部门经理, createTime=2014-05-02 16:49:06.0

c) 部门经理办理任务:提交申请环节

@Test
	public void completeTask() {
		String taskId = "30001";
		processEngine.getTaskService().completeTask(taskId);
	}

d) 部门经理执行完任务,即 部门经理审批环节结束,环节进行到 to总经理审批,此时部门经理再查询个人任务列表结果为空。

5.总经理操作

a) 查询未办理的任务列表

@Test
	public void findMyTaskList() {
		// 查询任务
		String userId = "总经理";
		List<Task> list = processEngine.getTaskService().findPersonalTasks(userId);

		// 显示任务
		System.out.println("========= 【"+userId+"】的未办理的任务列表 =========");
		for (Task task : list) {
			System.out.println("id=" + task.getId()//
					+ ", name=" + task.getName()//
					+ ", assignee=" + task.getAssignee()//
					+ ", createTime=" + task.getCreateTime());
		}
	}

b) 查看到任务id为40001

========== 【总经理】的未办理的任务列表 =========

id=40001, name=总经理审批, assignee=总经理, createTime=2014-05-02 16:49:33.0

c) 总经理办理任务:提交申请环节

@Test
	public void completeTask() {
		String taskId = "40001";
		processEngine.getTaskService().completeTask(taskId);
	}


d) 总经理执行完任务,即 总经理审批环节结束,环节进行到 to end1,此时总经理再查询个人任务列表结果为空。

6.流程实例执行完毕,此时jbpm4_execution表为空,历史记录表:jbpm4_hist_procinst出现一条记录


作者:v123411739 发表于2014-5-2 17:32:34 原文链接
阅读:93 评论:0 查看评论

FTP/SFTP/SSH的一些软件包

$
0
0
1.软件

1.1服务端
  • IIS,Windows自带,可以到[打开或关闭windows功能]里选择IIS,进行安装
  • FileZilla
  • freeSSHd ,支持FTP/SFTP/SSH
  • OpenSSH这个是Linux上的SSH标配,Windows上则可以通过cygwin的方式来安装


1.2 客户端


2.Java API
  • commons-net,貌似只支持FTP
  • JSch,支持SFTP/SSH,一些有名的开源软件都用了它
  • SSHTools,支持SFTP/SSH


3.一些值得参考的资料
方便的FTP客户端封装(apache.commons.net.ftp)
当然最全的软件列表还是去维基百科去查吧。



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


ITeye推荐



下一代OS X将被重新设计,再次向iOS看齐

$
0
0

syrah_icloud_hero

两年前,苹果公司在发布其新一代桌面操作系统Mac OS X 10.7 Lion的时候,打出了“Back to the Mac”的标语。这个标语的意思是,iOS诞生之初借鉴了许多Mac OS X的元素,而在OS X Lion系统中,苹果将一些iOS上大获成功的特性移植了回来。

实际上,从视觉界面到软件功能,苹果旗下的两个操作系统——OS X和iOS从未停止过互相“学习”。而iOS7的用户界面在Ive主导下被重新设计过之后,不断有传言称下一代的OS X也将会遵循iOS的脚步,并将于今年6月的WWDC2014大会上对外公布出来。

根据9to5Mac的 报道,在一个月之后举办的WWDC2014上,下一代的OS X——OS X 10.10将会比iOS8更让人期待。9to5Mac引用接近这个项目的消息源称,OS X 10.10将会得到从代码层面到用户界面的重新设计,而正因如此,苹果也会像重新设计过iOS7之后那样,向开发者大力推广它的新一代的桌面操作系统,促使开发者们也做出配合。与此同时,苹果也已经将一部分iOS的设计人员调配到OS X设计团队来推进开发进度。

新设计将会向iOS7看齐,采用更锋利的窗口棱角,更清晰的系统图标,以及比现有版本更多的留白,比起目前的视觉效果更“扁平化”。当然,OS X作为一个桌面操作系统的特有功能如Finder(文件浏览器)、多窗口多任务以及Mission Control功能都将会保留下来。

同时,新的操作系统将会在今年秋季放出,到时候苹果将会更新旗下的Mac硬件产品,搭载新的操作系统发售——这是苹果惯用的发布节奏。

虽然目前没有关于新版操作系统的截图流出,但我们可以从苹果最新的软件中看到设计风格的变化。比如最新版的iWork套件和OS X mavericks内置的iBooks、备忘录等应用,都采用了此前没有过的扁平化的视觉元素。

pages

memos

不过,OS X 10.10的最终代号仍未确定下来。此前有消息称,这款操作系统的代号将会为“Syrah”。

相关阅读:

     是时候让可穿戴计算“回归算法”了

     绕过苹果的“应用内购买”政策,亚马逊最积极

     相比较奔驰、宝马,沃尔沃正在聪明的使用CarPlay

     【Pingraphic】互联网公司的能源竞赛

Facebook是如何挑选和招募设计师人才的?

$
0
0

  对于想要进入技术行业的设计师来说,Facebook或许是他/她梦想成真的地方。

  Facebook的产品设计主管朱丽叶周(Julie Zhou)在接受媒体采访时披露了公司是如何挑选设计师人才的。她在2006年加盟Facebook担任产品设计师,当时她只有22岁。

  Facebook如何发现人才?

  朱丽叶周说:“寻找最佳人才的最佳途径就是研究你叹赏的产品,然后搞清楚它们是由谁设计出来的。”

  换句话说,要想成功地进入Facebook,首先就要拿出一些你设计的并且能够打动他们的产品。

  做好接受详细审查的准备

  在求职应聘的流程刚刚开始的时候,Facebook会召见所有的求职者并亲自审查他们的作品。

  朱丽叶周说:“你必须看看他们做了些什么,亲自详细分析他们的作品。”

  她会看看那款产品是否解决了实际性问题,是否易用,外观是否精美。她是这样说的:“我们不会仅仅从功能的角度去考核产品。我们希望产品能够让人们感觉到产品的设计者是真正关心他们和他们的个人体验的。那种高品质和工艺对我们来说非常重要。”

  有时候,应聘者带来的他们早期版本的设计作品给朱丽叶周留下了深刻的印象。她说,这些设计作品可以让你更深入地了解以后可能与你共事的这个人。

  常春藤联盟的学位证书并不是必要条件

  虽然Facebook肯定从享有盛名的高等院校招募了不少人才,但是它也有很多才智超群的设计师和开发员是自学成才的。

  朱丽叶周说:“有时,没有接受过传统教育的设计师反而会具备罕见的天赋。我们真的需要那种做事非常积极的人才。即便他们上过名校,他们也应该因为参与过校内和校外的很多研究项目而拥有丰富的经验。好的人才应该亲自参与过产品试验、设计和生产的流程。”

  证明你是一名注重团队合作的人才

  即便是最棒的设计师,如果不能很好地与其他人共事,他也不会被Facebook聘用。

  在面试的过程中,Facebook经常会让应征者尝试与另外的3到4名设计师合作,看看整个团队的工作效率如何。这方面的考核还包含了对其他设计师的工作成果的考核和应征者对其他设计师的工作成果的评价。

  一些样本问题

  朱丽叶周说,作为一名设计师,最重要的品质是思维缜密。她准备了一些面试问题来判断设计师的思维是否缜密周全。

  例如,她会提出这样的问题:“如果你有两个月的时间来做这个项目,你的工作成果会有何不同之处?你会增加些什么东西或是继续做精益求精的工作?”

5种实用的移动手机APP导航菜单设计方案

$
0
0

手机分辨率比桌面平台小很多,所以设计手机网站或是移动应用的时候,导航菜单都需要考虑周全,尽量保持简约和易用性高,这里我们整理了5种实用的移动手机APP导航菜单设计方案,你可以尝试这些菜单设计模式用在你的新设计项目上,好用而且有新鲜感。

扩展阅读:《 使用垂直的导航菜单设计》、《 有特色的使用大菜单的网页设计》、《 20个极简网页菜单导航设计

这5种APP菜单设计方案也许有很多设计师已经在使用,但不能否认它是目前实用的,而且能提高用户体验的菜单设计方案。下面摘选移动手机 UI设计美观、时尚,希望你看了后会有灵感收获,能把你的菜单设计得更棒,好好学习吧:)

APP 导航设计类型:

  1. 列表式菜单
  2. 矩阵、网格式菜单
  3. 底部菜单
  4. 顶部菜单
  5. 扩展菜单

1. 列表式菜单

列表式菜单设计这个从网站到手机APP上都很常用的,遵循由上至下的阅读习惯方式,所以使用起来用户不会觉得困难。另外我们可以通过漂亮的配色、图标组合来设计,使得菜单更多加美观。

GIF Aimation by Sergey Valiukh

GIF Aimation by Sergey Valiukh 菜单设计 APP设计
查看原图

Elevatr by Fueled

Elevatr by Fueled 导航菜单设计
查看原图

HabitClock App by Kutan

HabitClock App by Kutan URAL 菜单设计 APP设计
查看原图

Instagrab for iOS by Davis Yeung

Instagrab for iOS by Davis Yeung 导航设计 界面设计
查看原图

 

2. 矩阵、网格式菜单设计

网格式菜单就类似于metro UI的堆砌色块,优点简约而不简陋,导航清晰、明显,并能提高效率。但设计时切记不分青红皂白的去使用色彩哦,这可能会让用户不知所措和产生疲倦感。

Vectra  by Michal

vectra - branding by Michal Galubinski and thoke design 导航设计 界面设计
查看原图

Arrivo Mobile App by Marco

Arrivo Mobile App 导航设计 界面设计
查看原图

Abracadabra App by Sergey

Abracadabra App by Sergey Valiukh 导航设计 界面设计
查看原图

T R A V E R S E by Willis

T R A V E R S E by  Willis 菜单设计 APP设计
查看原图

3. 底部菜单

底部菜单主要是列出应用程序重要的功能。

Badoo concept by Jakub Antalík

Badoo concept by Jakub Antalik 菜单设计 APP设计
查看原图

Animated sliding tab bar by Virgil Pana

Animated sliding tab bar by Virgil Pana UI界面设计
查看原图

4. 顶部菜单

顶部菜单和底部意义差不多,把菜单放在顶部,可以遵循上至下的阅读习惯,不过我认为有个缺点就是不能单手操作。

Horner by Cüneyt ŞEN

Horner by Cuneyt SEN UI界面设计
查看原图

Discovery Channel by Enes Danış

Discovery Channel UI界面设计
查看原图

Air flow calculation app by HAMZAQUE

UI设计
查看原图

Shario App by MING Labs&Pierrick Calvez

Shario App by MING Labs&Pierrick Calvez 航行设计 UI设计
查看原图

5. 扩展菜单

扩展式菜单设计现在连网站也很常用,当我们觉得菜单比较点用位置的时候,可以尝试用这种方式来隐藏菜单,需要注意的是设计展开菜单按钮大部设计在左或右上角这些显示的位置。

MuSeek by Al Power

MuSeek by Al Power 菜单设计 APP设计
查看原图

Univit UI by Mohammed Alyousfi & Àlex Casabò

Univit UI by Mohammed Alyousfi & Alex Casabo 菜单设计 APP设计
查看原图

SVOY app design by Alexandre Efimov

SVOY app design by Alexandre Efimov 菜单设计 APP设计
查看原图

Időkép by Attila Szabó

Idokep by Attila Szabo 菜单设计 APP设计
查看原图

总结

从上面5个菜单设计方案中可以看出都有自己的优缺点,所以我们应该选择对你项目最为有效的方案,并能提高用户体验。


Copyright ©2010-2014 ¦ RSS订阅¦ 新浪微博¦ 本文链接¦ 添加评论
交流:UI设计交流群:59300679,与500名设计师交流设计,分享素材。

C2B的未来:大数据定制

$
0
0

昨天看到微信SuperSofter写了一篇文章,有感而发,以便备记。


这是一种典型的C2B模式。阿里不只是在与腾讯拼移动,它的电商本土业务也在稳步推进。最近一个里程碑事件是,阿里包下了美的、九阳、苏泊尔等十个品牌的12条生产线,专为天猫特供小家电。阿里通过所掌握的数据以及分析成果,去指导这些生产线的研发、设计、生产、定价。

C2B与规模化之间的矛盾

C2B反向定制模式大家并不陌生。这是用户需求驱动的产品生产模式。百度百科对其的解释是,消费者根据自身需求定制产品和价格,或主动参与产品设计、生产和定价,产品、价格等彰显消费者的个性化需求,生产企业进行定制化生产。

最为业界所熟知的莫过于戴尔,通过直销网站实现了用户先定制方案,戴尔再组织生产。手机行业出现了青橙、百分之百等定制手机,用户可以选择手机配置、外壳颜色、预装应用等。Ipad则支持雕刻用户名字和指定文字,在广州有一家被汪洋副总理盛赞的C2B家居电商:尚品宅配家居网,用户可以在它的网站深度定制家居产品。之前SuperSofter还曾报道过上汽的MG5极客版汽车采用C2B模式满足用户个性化需求,用户可选择配置、座椅、系统、保险、车贷,甚至语音助手对主人的“称呼”。     

这些定制均是以满足用户的个性化需求为首要目标,而个性化与规模化之间往往是矛盾的。同时,会增加成本。如果厂商需要为每个人制作一个特定的产品,必然带来生产成本的大幅提升,一些浅层的定制例如名称雕刻由于有成熟的技术尚能应付,但一些复杂的定制就只能在单品利润很高的家居这样的行业才能实现了。

平衡个性化与规模化的C2B

第一种是通过成熟的模块组合快速形成个性化,而这些个性化方案可以满足一个群体的需求,基于此实现了一定的规模化。戴尔、青橙手机就属于此类。此前,已经有一些电商卖家在天猫进行这样的尝试,用户下单时可以选择一些组合,厂家据此进行生产。这样的C2B定制,用户能够定制左右的并不多,厂家的逻辑也是在短时间内收集一定数量的某类需求快速进行生产满足,这对供应链要求较高。这种模式被成为“模块化定制”。

第二种则是让潜在用户参与到产品的设计之中。实际上这与C2B关系并不大,因为自从产品经理这个职位出现之后,几乎所有产品都会注重实现去了解用户需求再进行产品设计。小米等互联网公司将这个做成了粉丝经济,让粉丝通过互联网更加充分地产于到对未来产品功能的讨论、投票中来,然后快速迭代进行满足。本质上,这只不过将需求调研的用户样本扩大了。海尔还曾在天猫组织一次投票活动,让用户对一款冰箱的一些候选功能进行投票表决。这种模式可以被成为“群体调研定制”。

第三种是先收集需求再生产的预售模式。这时候厂商实现收集的不是用户的个性化需求,厂家只关心用户有没有这样的需求,有就先下单交钱。这样做的目的既可以提前一步得到货款,又可以最大化降低库存,甚至还可以通过控制预售规模做饥饿营销。小米对此模式游刃有余,现在智能硬件行业十分亲睐此模式,众筹网站被很多智能硬件作为预售网站。当然,团购其实也是这样的模式,先组织大规模订单,商家为此进行备货、生产或者服务准备。

模块化定制、群体调研定制和预售模式均可以最大限度地降低个性化的成本,在规模化的同时又可以满足一些群体具有交集的个性化需求,它让一部分人群可以个性化。更多是为了节省生产资源、降低库存压力、提高产销比。

未来的C2B:基于大数据

上面的种种C2B模式,用户都需要主动参与其中。互动、调研、预售、团购、定制、选配都是主动行为。天猫包下生产线的方式则给大家带来了耳目一新的方式,它同样可以指导各大品牌商的设计、生产、定价,但用户却是被动地参与这个过程。

用户的搜索浏览、驻留时间、商品对比、购物车、下单、评价数据被天猫全程记录,同时用户的个人资料例如性别、地域、年龄、职业、消费水平、偏好、星座天猫早已进行画像。这时候天猫可以对用户进行交叉分析、定点分析、抽样分析、群体分析。大数据挖掘落地就得靠这些手段。

天猫数据分析的结果,可能是用户不喜欢卧式吸尘器的垃圾倾倒设计,因为需要弯腰。也可能是广东用户更需要吹风机因为广东天气湿热,还可能是挂烫机使用频率不够。这些结果自然可以帮助到小家电进行特别的功能设计。除了指导功能之外,天猫还可以通过地域和时间分析指导生产线不同季节的产量和不同地域的库存。

在去年底天猫已经启动了数据共享计划, 将它们沉淀的行业数据分享给厂商,从价格分布、关键属性、流量、成交量、消费者评价等维度建模,挖掘出功能卖点、主流价格段分布、消费者需求、增值卖点来指导厂家的研发、设计、生产。现在天猫认为这样的模式可以复制到更多厂家,因为开始去承包生产线,引入更多厂商。

这是一种用户不知不觉参与的C2B模式,可以总结为“大数据定制”。它即帮助厂家更好地满足用户的需求,也有助于帮助厂家减少库存、提升销量。规模化的结果是用户和厂家一起瓜分减少的成本。这种C2B模式的C是全网用户,并不需要兴师动众地组织团购,组织投票,组织调研。

要做到大数据定制必须具备几个条件:1、有海量的数据;2、这些数据能够挖掘出对生产商家有指导价值的结果;3、具备挖掘这样的数据的技术能力;4有能力整合生产、流通和销售这些关键环节。具有此能力的企业并不多。

未来这种基于大数据的C2B模式将会从小家电扩展到服装、3C、家居以及一些长尾品类。在包下生产线之外,天猫还会尝试其他的一些大数据C2B定制模式,例如有偿提供大数据成果给一些厂家,其他电商卖家以及普通互联网巨头也会纷纷跟进。大数据正在以多种方式落地,C2B成为受益于大数据的应用。大数据C2B时代已到来。 (博客同步网址)

作者:www19940501a 发表于2014-5-3 0:28:34 原文链接
阅读:178 评论:0 查看评论

Facebook 推出 App Links 开发者工具意在解决什么问题?

$
0
0
App Links 并不是用来取代 URL Scheme 的,所以也谈不上「有何本质不同」。它并不是某一种技术,而是一项协议(或者像他们说的,一种「解决方案」)。

我们想像一下这样一个常见的场景:A 在大众点评上看到了一家餐厅并想通过微信把这家餐厅分享给 B——此时问题出现了——B 会如何处理这个链接是未知的。如果 A 和 B 都是同一平台的用户还好,当时直接传一个类似于 dianping://shop/12345 的 URL 对方在微信中点了就能在 app 里打开了(先不考虑微信是否接受这样的 URL)。可是如果大众点评某天升级了把 URL scheme 改成 dianping_v2://shop/12345 呢?如果 A 和 B 是两个不同平台的用户呢?如果 B 的手机上根本就没有装大众点评呢?

这个事情,大众点评即使想做也是有心无力——链接一旦分享出去控制权就不在自己手里了。好吧,我们还是可以做一个网页版的嘛,弄一个 http://m.dianping.com/shop/4551072 这样的链接,不管对方是什么环境,至少可以在微信的 in-app 浏览器里打开嘛。牺牲部分体验来换取最大的可用性——而且还是有活路的,可以在网页加载好后用 JavaScript 做一点 window.location.href = 'dianping://shop/12345' 这样的小动作嘛——直到有一天微信关掉了 URL Scheme 跳转……

于是这个事情就变得很荒唐。明明对方的手机里有装大众点评的 app,大众点评也支持 URL Scheme,可在微信上点开大众点评的链接就是只能看到 web 版。理论上来说作为平台的微信应该出来挑大梁,不过可能微信忙着征服全世界顾不上这点小事——于是另一个闲得没事干的平台 Facebook(好吧,准确地说是 Facebook 去年买进来的 Parse 团队)跳出来解决了问题。

怎么解决?说难也不难,无外乎就是把自己在几个平台下的跳转规则一并告诉对方。对方是什么平台就按什么平台的规则去处理。如果对方没装我们的 app,那我就告诉他一个安装地址。如果他的平台确实没有我们的 app(并没有想黑 WP 的意思……),那么就给他看一个网页版好了。但是这些规则写在哪呢?用 <meta> 标签放在网页里就好了嘛!于是一个实现了 App Links 的网页大致长成这样:

<html><head><meta property="al:ios:url" content="applinks://docs" /><meta property="al:ios:app_store_id" content="12345" /><meta property="al:ios:app_name" content="App Links" /><meta property="al:android:url" content="applinks://docs" /><meta property="al:android:app_name" content="App Links" /><meta property="al:android:package" content="org.applinks" /><meta property="al:web:url"
          content="http://applinks.org/documentation" /></head><body>
Hello, world!</body></html>

大众点评网的程序员们看到之后如获至宝,嗨嗨皮皮(不要质疑我的成语能力!)地把这些 meta tags 都塞进了 http://m.dianping.com/shop/4551072 。Parse 说我都给你们写好各个平台下的 SDK 了,解析跳转一条龙哦你们赶紧用。腾讯(过了一年后)说,App Links 是什么?

App Links 还制定了一些别的标准,比如可以多次指定同一项值来完成 fallback(用于新老版本 URL Scheme 不兼容的情况),比如实现了跳转时的数据传输标准(用 JSON 描述,放在 al_applink_data 参数中),比如提供了跳转后 app 的 UX 建议(导航栏用一层蓝色的可点按区域覆盖,点按后返回原 app)。App Links 不是唯一解,也不一定是最优解,但它确实是解决当下 app 间跳转混乱局面的一个可行解(而且标准本身具有可扩展性,即使 iOS 8 里加入类似 Android 中的 Intent,App Links 也可以通过增加几个 meta tags 来支持)。回到最初的问题上,它解决的问题,其实就是 Ilya Sukhar (Parse CEO) 在 F8 上说的这句话:「There is no unified way to navigate to links across all the platforms.」在技术层面上,App Links 统一了流程、跨了平台,这就很好了。

而剩下的问题其实才是最大的问题——有人用的标准才是好标准。这个用也分两种角色:类似大众点评这样的第三方开发者,他们只需要发布自己的 App Links 就可以了,这个事情很简单,如上面所说无非就是在现成的网页里加几个 meta tags 的事情。而类似微信这样的平台则需要实现这样的协议,理论上也不难,但也许除了优化用户体验之外好处有限,可能还会面临到如何去兼容老版本啦、跳转出去会不会降低用户黏性啦、怎么满足平台的统计需求啦之类的问题(随口一说,也许没那么多问题。)老外比较单纯,想想这对用户来说是件好事我们就做吧,于是至少 Parse 有他的亲爹 Facebook 给他撑腰。至于国内,需要有第一个吃螃蟹的人。

— 完 —
本文作者: 罗晟

【知乎日报】 你都看到这啦,快来点我嘛 Σ(▼□▼メ)

此问题还有 2 个回答,查看全部。
延伸阅读:
测试 iOS App 时需要注意什么?
scrum工具大家有什么推荐?

php学习高级-提高PHP编程效率的几点建议

$
0
0

1、如果能将类的方法定义成static,就尽量定义成static,它的速度会提升将近4倍。

2、$row[’id’] 的速度是$row[id]的7倍。

3、echo 比 print 快,并且使用echo的多重参数(译注:指用逗号而不是句点)代替字符串连接,比如echo $str1,$str2。

4、在执行for循环之前确定最大循环数,不要每循环一次都计算最大值,最好运用foreach代替。

5、注销那些不用的变量尤其是大数组,以便释放内存。

6、尽量避免使用__get,__set,__autoload。

7、require_once()代价昂贵。

8、include文件时尽量使用绝对路径,因为它避免了PHP去include_path里查找文件的速度,解析操作系统路径所需的时间会更少。

9、如果你想知道脚本开始执行(译注:即服务器端收到客户端请求)的时刻,使用$_SERVER[‘REQUEST_TIME’]要好于time()。

10、函数代替正则表达式完成相同功能。

11、str_replace函数比preg_replace函数快,但strtr函数的效率是str_replace函数的四倍。

12、如果一个字符串替换函数,可接受数组或字符作为参数,并且参数长度不太长,那么可以考虑额外写一段替换代码,使得每次传递参数是一个字符,而不是只写一行代码接受数组作为查询和替换的参数。

13、使用选择分支语句(译注:即switch case)好于使用多个if,else if语句。

14、用@屏蔽错误消息的做法非常低效,极其低效。

15、打开apache的mod_deflate模块,可以提高网页的浏览速度。

16、数据库连接当使用完毕时应关掉,不要用长连接。

17、错误消息代价昂贵。

18、在方法中递增局部变量,速度是最快的。几乎与在函数中调用局部变量的速度相当。

19、递增一个全局变量要比递增一个局部变量慢2倍。

20、递增一个对象属性(如:$this->prop++)要比递增一个局部变量慢3倍。

21、递增一个未预定义的局部变量要比递增一个预定义的局部变量慢9至10倍。

22、仅定义一个局部变量而没在函数中调用它,同样会减慢速度(其程度相当于递增一个局部变量)。PHP大概会检查看是否存在全局变量。

23、方法调用看来与类中定义的方法的数量无关,因为我(在测试方法之前和之后都)添加了10个方法,但性能上没有变化。

24、派生类中的方法运行起来要快于在基类中定义的同样的方法。

25、调用带有一个参数的空函数,其花费的时间相当于执行7至8次的局部变量递增操作。类似的方法调用所花费的时间接近于15次的局部变量递增操作。

26、Apache解析一个PHP脚本的时间要比解析一个静态HTML页面慢2至10倍。尽量多用静态HTML页面,少用脚本。

27、除非脚本可以缓存,否则每次调用时都会重新编译一次。引入一套PHP缓存机制通常可以提升25%至100%的性能,以免除编译开销。

28、尽量做缓存,可使用memcached。memcached是一款高性能的内存对象缓存系统,可用来加速动态Web应用程序,减轻数据库负载。对运算码 (OP code)的缓存很有用,使得脚本不必为每个请求做重新编译。

29、当操作字符串并需要检验其长度是否满足某种要求时,你想当然地会使用strlen()函数。此函数执行起来相当快,因为它不做任何计算, 只返回在zval 结构(C的内置数据结构,用于存储PHP变量)中存储的已知字符串长度。但是,由于strlen()是函数,多多少少会有些慢,因为函数调用会经过诸多步 骤,如字母小写化(译注:指函数名小写化,PHP不区分函数名大小写)、哈希查找,会跟随被调用的函数一起执行。在某些情况下,你可以使用isset() 技巧加速执行你的代码。

(举例如下)

if (strlen($foo) < 5) { echo “Foo is too short”$$ }

(与下面的技巧做比较)

if (!isset($foo{5})) { echo “Foo is too short”$$ }

调用isset()恰巧比strlen()快,因为与后者不同的是,isset()作为一种语言结构,意味着它的执行不需要函数查找和字母小写化。也就是说,实际上在检验字符串长度的顶层代码中你没有花太多开销。

34、当执行变量$i的递增或递减时,$i++会比++$i慢一些。这种差异是PHP特有的,并不适用于其他语言,所以请不要修改你的C或 Java代码并指望它们能立即变快,没用的。++$i更快是因为它只需要3条指令(opcodes),$i++则需要4条指令。后置递增实际上会产生一个 临时变量,这个临时变量随后被递增。而前置递增直接在原值上递增。这是最优化处理的一种,正如Zend的PHP优化器所作的那样。牢记这个优化处理不失为 一个好主意,因为并不是所有的指令优化器都会做同样的优化处理,并且存在大量没有装配指令优化器的互联网服务提供商(ISPs)和服务器。

35、并不是事必面向对象(OOP),面向对象往往开销很大,每个方法和对象调用都会消耗很多内存。

36、并非要用类实现所有的数据结构,数组也很有用。

37、不要把方法细分得过多,仔细想想你真正打算重用的是哪些代码?

38、当你需要时,你总能把代码分解成方法。

39、尽量采用大量的PHP内置函数。

40、如果在代码中存在大量耗时的函数,你可以考虑用C扩展的方式实现它们。

41、评估检验(profile)你的代码。检验器会告诉你,代码的哪些部分消耗了多少时间。Xdebug调试器包含了检验程序,评估检验总体上可以显示出代码的瓶颈。

42、mod_zip可作为Apache模块,用来即时压缩你的数据,并可让数据传输量降低80%。

43、在可以用file_get_contents替代file、fopen、feof、fgets等系列方法的情况下,尽量用 file_get_contents,因为他的效率高得多!但是要注意file_get_contents在打开一个URL文件时候的PHP版本问题;

44、尽量的少进行文件操作,虽然PHP的文件操作效率也不低的;

45、优化Select SQL语句,在可能的情况下尽量少的进行Insert、Update操作(在update上,我被恶批过);

46、尽可能的使用PHP内部函数(但是我却为了找个PHP里面不存在的函数,浪费了本可以写出一个自定义函数的时间,经验问题啊!);

47、循环内部不要声明变量,尤其是大变量:对象(这好像不只是PHP里面要注意的问题吧?);

48、多维数组尽量不要循环嵌套赋值;

49、在可以用PHP内部字符串操作函数的情况下,不要用正则表达式;

50、foreach效率更高,尽量用foreach代替while和for循环;

51、用单引号替代双引号引用字符串;

52、“用i+=1代替i=i+1。符合c/c++的习惯,效率还高”;

53、对global变量,应该用完就unset()掉;

作者:jiangtao_st 发表于2014-5-3 17:04:36 原文链接
阅读:84 评论:0 查看评论

需求用例分析之异常流

$
0
0

问题的引出

备选流,又称备选事件流,英文是Alternative Flow。在RUP和UML中,备选流的解释如下:备选事件流包括与正常行为相关的可选或异常特征的行为,同时也包括正常行为的各种变形。您可以将备选事件流看作是基本事件流的“绕行道”,有些备选事件流将返回到基本事件流,而有些将结束此用例的执行。 

分析RUP对于备选流的定义,可以看到备选流可以分成两类:

1,不同做法但仍然达成用例目标;

2,异常情况,无法达成用例目标。

 

在实际用例分析中,由于备选流可能存在两种情况,导致备选流存在2种主要写法:

1.在备选流中说明基本流以外的异常情况的处理,可能仍然回到基本流,也可能导致用例结束。

在备选流中说明基本流以外的其它正常和异常情况的处理,覆盖了其它功能。

第1种写法的例子比较常见,下文将出现,这里不再赘述。

第2种写法的例子如下:

用例名称:填写请购单

简要说明

  员工在线填写图书请购单,内容包括:图书名称、出版社、作者、价格、订购人(系统自动识别)、订购部门、订购日期等,填好后提交给图书管理员审核。

  填写请购单的主角是员工。

事件流

  员工选择“填写请购单”,用例开始。

基本流

员工选择“填写请购单”,提交“填写请购单”请求;

显示“填写请购单”窗口并列表显示请购单信息(已填写未提交、已提交审核未通过), 两种状态的请购单信息通过选择分别列出,审核未通过的原因只能查看不能修改;

请购单信息包括:请购单编码(系统自动生成)、订购部门、订购人、订购日期、订购原因、备注,和图书明细包括:图书名称、出版社、作者、单价、数量等,图书明细包括:新增,修改,删除;

请购单信息输入操作见备选流;

新增:系统具体执行见“备选流 新增”

修改:系统具体执行见“备选流 修改”

删除:系统具体执行见“备选流 删除”

选择“提交”,系统把选中的请购单提交给图书管理员审核,此用例结束。

 备选流

  填写请购单基本流中抽取出三个备选流:

    请购单信息:新增、修改、删除;

新增

(一)员工在“填写请购单”信息区选择“新增”,提交“新增”请求;

(二)系统弹出“新增请购单”空白模式窗口;

(三)请购单信息包括:图书名称、出版社、作者、单价、数量等;

(四)请购单信息输入完毕后,选择“保存”提交,系统验证数据有效性,如验证不成功,针对所提示错误信息修正输入数据,验证成功关闭“新增请购单”窗口;

若继续新增请购单,则重复㈠㈡㈢㈣步骤。

修改

(一)员工在“填写请购单”信息区列表选中要修改的请购单,提交“修改”请求;

(二)系统弹出“修改请购单”模式窗口,并显示当前请购单信息;

(三)修改相应数据后,选择“保存”提交,系统验证数据有效性,如验证不成功则根据错误提示重新输入,验证成功后保存数据并关闭“修改请购单”模式窗口同时刷新请购单信息列表;

若继续修改,则重复㈠㈡㈢步骤。

删除

(一)员工在“填写请购单”信息区列表选中要删除的请购单,提交“删除”请求;

(二)若选中的请购单属于审核未通过,系统提示“不能删除审核未通过的请购单”;

(三)删除后刷新请购单列表信息同时系统提示“编号为XXX的请购单已删除!”;

若继续删除,则重复㈠㈡㈢步骤。

 

特殊需求

  无

前置条件

  员工登录系统。

后置条件

  无

---例子结束----

第2种写法中,在备选流中说明了基本功能,用例篇幅已经变长,如果备选流中出现异常,备选流将显得更加臃肿。因此第2种写法比较少见。

为了解决备选流的不同情况,人们识别率异常流来解决上述问题。

异常流是什么?

Bernd Lohmeyer提出来如下分类规则

(见 http://www.lohmy.de/2013/03/06/writing-use-cases-exception-or-alternate-flow/  )

l Result negative: An Exception is anything that leads to NOT achieving the use case’s goal. 负面结果:异常,任何导致不能达成用例目标的事情

l Result positive: An Alternate Flow is a step or a sequence of steps that achieves the use case’s goal following different steps than described in the main success scenario. But the goal is achieved finally. 正面结果:备选流,一步或多个步骤序列达成了用例目标,但与主成功场景不一样的步骤。最终目标是达成的。

见如下例子:


简单说:异常流是基本流的异常情况,不能达成用例目标。

用异常流替代备选流

苍狼敏捷需求用例分析方法对于备选流的做法是采用第1种做法,但用异常流替代备选流,从名称上排除第2种做法,满足用例目的的可选流程在基本流中表达,如果导致基本流篇幅过长,那么就分拆用例。

对照到上述“填写请购单”的例子,苍狼敏捷需求用例分析方法至少分拆成如下多个用例:

1,新增请购单

2,修改请购单

3,删除请购单

其中新增请购单的用例规约

用例属性

说明

名称

新增请购单

简要说明

员工在线填写图书请购单,内容包括:图书名称、出版社、作者、单价等,填好后提交给图书管理员审核。

前置条件

员工已经登录

启动点

员工在“填写请购单”信息区选择“新增”,提交“新增”请求,系统弹出“新增请购单”空白模式窗口

基本流

1. 员工填写各项请购单信息,包括图书名称、出版社、作者、单价、数量、订购原因、备注,员工请购单信息输入完毕后,选择“保存”提交

2. 系统验证数据有效性,有效性规则见X.Y

3. 系统验证如果通过,记录此请购单

4. 系统返回“保存”成功信息

异常流

3b如果验证不成功,给出具体字段的错误提示信息,让用户修正输入数据

后置条件

提交给图书管理员审核

特殊需求

请购单输入信息界面在一个屏幕内

扩展点

 

异常流的好处

根据以上分析,可以看到,异常流实质上是一种备选流,对照原RUP备选流说明的话,定义如下:异常流是与基本流正常行为相关的异常行为。
异常流不是基本流的“绕行道”,有些异常流将返回到基本流,有些将结束用例的执行。
异常流替代备选流主要的好处:
1,基本功能全部在基本流中表达
2,异常流从名称上清晰的明确了其定位:基本流的异常情况
3,基本流+异常流的组合可以覆盖所有事件流场景
4,用例的颗粒度将受到基本流篇幅的限制,有助于更精细的管理,有便于在敏捷开发环境下使用。


作者:zhangmike 发表于2014-5-3 14:54:30 原文链接
阅读:106 评论:0 查看评论

搜索引擎网页去重算法

$
0
0
  相关统计数据表明:互联网上近似重复的网页的数量占网页总数量的比例高达29%,完全相同的网页大约占网页总数量的22%.研究表明,在一个大型的信息采集系统中,30%的网页是和另外70%的网页完全重复或近似重复的。

    即:互联网的网页中相当高的比例的网页内容是近似相同或完全相同的!

搜索爬虫抓取会产生网页重复的类型
1.多个URL地址指向同一网页以及镜像站点  
    如:www.sina.com  和www.sina.com.cn
    指向同一个站点。
 
2. 网页内容重复或近似重复
    如抄袭、转摘的内容,垃圾信息等   
  
网页内容近似重复检测的两种应用场合:

 一:在用户搜索阶段
       
          目标是根据与用户给定的查询词找到已有索引列表中近似重复的文档,并排序输出。

二:爬虫抓取发现阶段
     对一个新的网页,爬虫程序通过网页去重算法,最终决定是否对其索引。
 

 
近似重复网页类型,根据文章内容和网页布局格式的组合分为4种形式:

一:两篇文档在内容和布局格式上毫无区别,则这种重复称为完全重复页面。

二:两篇文档内容相同,但布局格式不同,则这种重复称为内容重复页面。

三:两篇文档有部分重要的内容相同,并且布局格式相同,则这种重复称为布局重复页面。

四:两篇文档有部分重要内容相同,但布局格式不同,则这种重复称为部分重复页面。

重复网页对搜索引擎的不利影响:
正常情况下,非常相似的网页内容不能或只能给用户提供少量的新信息,但在对爬虫进行抓取、索引和用户搜索 会消耗大量的服务器资源。 

重复网页对搜索引擎的好处:
 如果某个网页重复性很高,往往是其内容比较比较受欢迎的一种体现,也预示着该网页相对比较重要。应予以优先收录。当用户搜索时,在输出结果排序时,也应给与较高的权重。

重复文档的处理方式:
1.删除
2.将重复文档分组

近似重复网页举例:



搜索引擎近似重复检测流程:


通用网页去重算法:


SimHash文档指纹计算方法 


1)从文档中提取具有权值的 特征集合来表示文档。如:假设特征都是由词组成的,词的权值由词频TF 来确定。  

2)对每一个词,通过哈希算法生成N位(通常情况是64位或更多)的二进制数值,如上图,以生成8位的二进制值为例。每个词都对应各自不同的二进制值。

3)在N维(上图为8维)的向量V中,分别对每维向量进行计算。如果词相应的比特位的二进制数值为1,则对其特征权值进行加法运算;如果比特位数值为0,则进行减法运算,通过这种方式对向量进行更新。

4)当所有的词都按照上述处理完毕后,如果向量V中第i维是正数,则将N位的指纹中第i位设置为1,否则为0。

  Jacccard相似性计算方法:


 如上图,A和B代表2个集合,集合C代表集合A和B相同的部分。 A集合包含5个元素,B集合包含4个元素,而两者相同的元素有2个,即集合C的大小是2. Jaccard计算两个集合相同的元素占总元素的比例。
如图中,集合A和集合B共有7个不同的元素,相同元素个数2个,所以集合A和集合B的相似性为:2/7

 

在实际应用中,集合A 和 集合B 的特征都会经过哈希计算,转化成N位(64位甚至更多)的二进制数值,从而将集合A和B的相似性比较转化为二进制数值的比较,称为“ 海明距离”的比较。两个位数相同(如均为64位)相同位置上不同的二进制数值的个数称为“海明距离”。


对给定的文档A,假设经过特征抽取--哈希指纹运算后的二进制数值是: 1 0 0 0 0 0 1 0

对给定的文档B,  假设经过特征抽取—哈希指纹运算后的二进制数值是:0 0 1 0 0 0 0 1


经过比较,文档A 和 B的 第1位、第3位、第7位、第8位四个位置的数值不同,即海明距离为4. 两个文档的二进制位数不同的个数越多,海明距离越大。海明距离越大,说明两个文档不相似性越大,反之,则越小。


不同搜索引擎可能会以不同的海明距离值 来判断两个网页内容是否近似重复。相关分析认为,一般情况下,对一个64位的二进制数值来说,将海明距离<=3作为判断是否近似重复的标准比较合理.



  青春就应该这样绽放   游戏测试:三国时期谁是你最好的兄弟!!   你不得不信的星座秘密

[原]网页去重-算法篇

$
0
0

前一篇提到了5个解决网页去重的算法,这里我想讨论下这些算法

1. I-Match

2. Shingliing

3. SimHashing( locality sensitive hash)

4. Random Projection

5. SpotSig

6. combined

I-Match算法
I-Match算法有一个基本的假设说:不经常出现的词和经常出现的词不会影响文档的语义,所以这些词是可以去掉的。
算法的基本思想是:将文档中有语义的单词用hash的办法表示成一个数字,数字的相似性既能表达文档的相似性
算法的框架是:
1. 获取文档(或者是主体内容)
2. 将文档分解成token流,移除格式化的标签
3. 使用term的阈值(idf),保留有意义的tokens
4. 插入tokens到升序排列的排序树中
5. 计算tokens的SHA1
6. 将元组(doc_id,SHA hash) 插入到某一词典中,如果词典有冲突,这两个文档相似。

算法有一个缺点是稳定性差。如果文档的某个词改变了,最终的hash值就会发生显著的变化。对空文档,算法是无效的。
有一个解决办法是,用随机化的方法,参考 Lexicon randomization for near-duplicate detection with I-Match。具体细节这里就不提了

Shingling算法
Shingling算法说,I-Match以词为单位做hash显然是不准确的,因为它忽略了文档之间的顺序。另,Shingle指的是连续的若干个单词的串。
Shingling算法有个简单的数学背景。如果一个shingle的长度为k,那么长度为n的文档就有n-k+1个shingle,每一个shingle可以用MD5或者其他算法表示成一个fingerprint,而两个文档的相似性Jacard相似性来表示,Jarcard公式是指两个集合的相似性=集合之交/集合之并。为了估计两个文档的相似性,有时候n-k+1个fingerprint还是太大了,所以取m个fingerprint函数,对每一个函数fi,都可以计算出n-k+1个fingerprint,取其中的最小的fingerprint,称为i-minvalue. 那么一个文档就有m个i-minvalue。数学上,Broder大师说:

        平均来讲,两个文档中相同的唯一single的比率和两个文档中相同的i-minvalue的比率是一样的

Shingling的算法框架是:
1. 获取文档(或者是主体内容)
2. 将文档分解成n-k+1个shingle,取m个fingerprint函数,对每一个fingerpint函数计算i-minvalue值
3. 将m个i-minvalue值组合成更少m’个surpersingle
4.计算两个文档相同的surpergingle的个数a。
5. 如果a大于某一个值b(say:2),那么两个文档Jarcard 相似

一般的参数设置为:m=84,m’=6,b=2

SimHash 算法

locality sensitive hash算法博大精深。基本思想是,如果两个东西相似,我可以用一个hash函数把他们投影到相近的空间中 LSH。用到near duplication detection上,算法框架是:
1. 将文档转换为特征的集合,每一个特征有一个权重
2. 利用LSH函数把特征向量转换为f位的fingerprint,如:64
3. 查找fingerprint的海明距离

haha,看,多么简单和明朗,这里的几个问题及时寻找正确的LSH

Random Projection算法
shingling关注了文档顺序,但是忽略了文档单词出现的频率,random projection说我要讨论文档的频率。

Random Projection也是很有意思的一种算法,它是一种随机算法。简单描述为:
1. 将每一个token映射到b位的空间。每一个维度是由{-1,1}组成。对所有页面投影函数是一样的
2. 每一个页面的b维度向量,是所有token的投影的简单加和
3. 最后把b维向量中的正数表示为1,负数和0都写成0
4. 比较两个page的b维向量一致的个数

Charikar最牛的地方是,证明,两个b位变量一致的位数的比率就是文档向量的consine相似性。这里的数学基础还是很有意思的,如果感兴趣,可以参考M.S. Charikar. Similarity Estimation Techniques for Rounding Algorithm(May 2002)

SpotSig算法

ref:SpotSigs:Robust and Efficient Near Duplicate Detection in Large Web Collection
SpotSig是个比较有意思的算法,它说,我为什么要关注所有的单词啊,我要关注的单词是有语义的词,哪些是有语义的词呢?哦,想 the a this an 的等虚词后面的就是我要关注的东西罗。Spot就是指这些虚词的后面的词串。然后呢,每一个文档我都有很多很多Spot了,现在一个文档就是一个Spot的集合,两个文档是相似程度就是集合的Jaccard相似度。算法虽然简单,但是我想重点是两个比较有借鉴意义的工程上的性能考虑。

     1. Optimal Partition

     Sim(A,B) = | A B交集| / | A B 并集| <= min(A,B)/max(A,B) <= |A|/|B| say: |A|<|B|

好了,这是一个很好的枝剪条件,如果文档spot vector的个数比小于某个值(当然是,小 / 大),就可以完全不用求交,并了。Optimal Partition就是说,好啊,我把每一个文档的spot vector的长度都投影到相应的从小到大的bucket中,保证|d1|/|d2| >=r if |d1| < |d2| . 且不存在这样的反例。另一个保证是这个bucket是满足条件的最小的。有了这个partition,我们最多只用关心相邻的三个bucket了

   2. Inverted Index Pruning

   说,两个文档,如果能相似,起码有一个公共的spot。逆向索引说的就是把spot做为index,包含它的所有文档作为其value。

有了这两个工具,计算复杂度可以明显下降,因为它不会计算不能是duplication的文档。
作者:beta2 发表于2009-12-15 22:15:00 原文链接
阅读:5150 评论:2 查看评论

大数据的价值密度

$
0
0

文 / 陈冠诚

注:原文刊载于《程序员》2014年第5期,略有删改。

在大数据和云计算如火如荼的今天,怎样将数据的商业价值变现成为各位老板和技术男们最关心的问题。马云经常讲,我不懂技术,所以我才要发力做云计算,做大数据。相信马总一定因为看到了云计算和大数据的潜在商业价值才做出上述决定的。在各位大佬争相跑马圈地的年代,各大公司都开始占领数据源头,从构建自己线上应用的生态圈入手,将用户的数据牢牢掌握在自己手中,以期望将来能从这些数据中挖掘出“潜在”的商业价值,例如在2014年风生水起的互联网金融行业就是其中典型。请注意,笔者这里专门对大数据的商业价值加上了“潜在”这两字。为什么需要这么关注这个字?其实这跟你的投资回报率非常有关系。

例如,大家都知道如果你能把新浪微博上的数据都扒拉下来,必然对很多生意都非常有帮助,例如各大电商网站,各大招聘网站等等。但是,你必须考虑清楚构建一个能存储和分析新浪微博数据的大数据平台的成本有多高,而你基于这些数据构建的解决方案能给你创造多大的商业价值。举例来说,电商网站可以通过微博数据进行社交推荐,也可以根据用户正在谈论的关键热词进行针对性的商品需求趋势预测并作针对性的营销。这些用法都很好,都能看到商业价值,可是,最关键的问题在于,如果你知道花五百万搭建整个大数据团队和平台,一年后只能为你的生意带来四百万的增长,你还愿意干这件事情吗?

这里面牵涉到一个很关键的因素:大数据的价值密度问题。要知道,存储和计算PB级的数据是需要非常高的成本的,大数据虽然看起来很美,但是价值密度却远远低于传统关系型数据库中已经有的那些数据。有一句话笔者很认同:“如果用石油行业来类比大数据分析,那么在互联网金融领域甚至整个互联网行业中,最重要的并不是如何炼油(分析数据),而是如何获得优质原油(优质元数据)”。以股市为例,真正有价值的数据都只会在很小范围内(例如庄家之间)传播,极少可能会流落到互联网上来,所以你如果想去只靠分析微博上网民对股票涨跌的评论来做行情预测的话,真的是要小心了。

阿里之所以牛气,就因为他掌握了全国上亿网民实名制的历史交易记录,这会成为将来阿里金融帝国最重要的资产。而像“挖财”这样的理财软件,则选择了围魏救赵的策略,用“免费”的噱头积累大量用户的理财数据,以便他日能转换成商业价值。而像雪球,知乎这样的高质量UGC社区,最大的资本也就是在于这些高价值密度的内容所拥有的巨大可能性。当年友盟被高价收购的时候,他们最大的资产也就是来自于他们所掌握的移动互联网领域的高价值数据。笔者愚见,当大家为各种层出不穷的大数据新技术而热血沸腾的同时,一定不要忘记了兄弟们用大数据的初衷,只是为了挖掘更大的商业价值而已。

回到刚刚提到的阿里巴巴金融数据,微博上的大数据怎么被更高效利用的问题,阿里和微博正在做的就是所谓Big-Data-As-a-Service的服务,所以你不需要自建一个专门用来存放淘宝和新浪微博海量数据的平台,产生不必要的成本浪费,而只需要根据自己的需求,直接通过阿里和微博提供的大数据服务的付费和免费接口,去对那些真正能对你产生价值的淘宝、微博数据进行分析,按需付费,实现双赢,甚至多赢。也许到那一天,我们才能真正在大数据的成本和收益之间取得一个很好的平衡,以创造更多的社会价值。

简而言之,玩大数据的时候,请一定要考虑清楚你所面对的数据的价值密度有多高,归根结底,商业的本质只是希望通过大数据挖掘更多的商业价值,仅此而已。


oracle执行计划

$
0
0

来自:

http://czmmiao.iteye.com/blog/1471756

 

执行计划概述 
所谓执行计划,顾名思义,就是对一个查询任务,做出一份怎样去完成任务的详细方案。举个生活中的例子,我从珠海要去英国,我可以选择先去香港然后转机,也 可以先去北京转机,或者去广州也可以。但是到底怎样去英国划算,也就是我的费用最少,这是一件值得考究的事情。同样对于查询而言,我们提交的SQL仅仅是 描述出了我们的目的地是英国,但至于怎么去,通常我们的SQL中是没有给出提示信息的,是由数据库来决定的。 
查看执行计划 
使用autotrace sqlplus系统参数:
SQL> set autotrace trace on
SQL> select * from dual;
DUM
---
X
Execution Plan
----------------------------------------------------------
Plan hash value: 272002086
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     1 |     2 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS FULL| DUAL |     1 |     2 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------
Statistics
----------------------------------------------------------
         24  recursive calls
          0  db block gets
          6  consistent gets
          4  physical reads
          0  redo size
        407  bytes sent via SQL*Net to client
        385  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed 
各个资源解释如下
Recursive Calls:

系统或者用户执行sql时需要执行的相关内部递归sql。具体解释可看下文
Number of recursive calls generated at both the user and system level.    
Oracle Database maintains tables used for internal processing. When it needs to change these tables, Oracle Database generates an internal SQL statement, which in turn generates a recursive call. In short, recursive calls are basically SQL performed on behalf of your SQL. So, if you had to parse the query, for example, you might have had to run some other queries to get data dictionary information. These would be recursive calls. Space management, security checks, calling PL/SQL from SQL—all incur recursive SQL calls。
Recursive calls can be generated by the following activities:
1、An object requiring an additional extent for storage (dynamic extension)
2、Misses on the dictionary cache
3、Firing of database triggers  
4、DDL statements
5、Execution of SQL statements within stored procedures, packages, functions, and anonymous PL/SQL blocks
6、Enforcement of referential integrity constraints
If Oracle is making an inordinate number of recursive calls, try to determine which of the previously listed activities is causing most of the recursive calls. Run the application through TKPROF with EXPLAIN PLAN to see what the application is doing.
Also, monitor the number of extents in the database to see if there is noticeable dynamic extension. If the recursive calls are caused by dynamic extension, you can reduce the number of calls by allocating larger extents to the relevant objects. A dictionary cache that is too small can also cause recursive calls. 
DB Block Gets(当前请求的块数目)
表示从当前内存中直接获取,而不是通过undo表空间构造的一致性读的块数目。
Consistent Gets(数据请求总数在回滚段Buffer中的数据一致性读所需要的数据块)
这里的概念 是在处理你这个操作的时候需要在一致性读状态上处理多少个块,这些块产生的主要原因是因为由于在你查询的过程中,由于其他会话对数据块进行操作,而对所要 查询的块有了修改,但是由于我们的查询是在这些修改之前调用的,所以需要对回滚段中的数据块的前映像进行查询,以保证数据的一致性。这样就产生了一致性 读。关于一致性读,读者可参考:
http://czmmiao.iteye.com/blog/1294307
Physical Reads(物理读)
就是从磁盘上读取数据块的数量,其产生的主要原因是:
1、 在数据库高速缓存中不存在这些块
2、 全表扫描
3、 磁盘排序
它们三者之间的关系大致可概括为:
逻辑读指的是Oracle从内存读到的数据块数量。一般来说是'consistent gets' + 'db block gets'。当在内存中找不到所需的数据块的话就需要从磁盘中获取,于是就产生了'phsical reads'。
Sorts(disk):
Number of sort operations that required at least one disk write. Sorts that require I/O to disk are quite resource intensive. Try increasing the size of the initialization parameter SORT_AREA_SIZE.
磁盘中的排序
bytes sent via SQL*Net to client:
Total number of bytes sent to the client from the foreground processes.
通过网络发送给客户端的数据
bytes received via SQL*Net from client:
Total number of bytes received from the client over Oracle Net.
通过网络从客户端接收到的数据 
SQL*Net roundtrips to/from client:
Total number of Oracle Net messages sent to and received from the client.
注意: autotrace 命令是先执行SQL,再出执行计划,如果SQL耗时巨大,则不现实。 
使用explain plan for语句:
SQL> explain plan for select * from dual;
    Explained.
SQL> select * from table(DBMS_XPLAN.display);
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 2137789089
    ---------------------------------------------------------------------------------------------
    | Id  | Operation                                                              | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
    ---------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT                                       |                   |  8168   | 16336 |    21   (0)| 00:00:01 |
    |   1 |  COLLECTION ITERATOR PICKLER FETCH| DISPLAY |             |       |
    |     |
    --------------------------------------------------------------------------------------------- 
这样就可以在执行SQL之前查看执行计划了
设置SQL_TRACE参数
设置当前session的 SQL_TRACE 
SQL> alter session set SQL_TRACE=true;
SQL> select * from dual;
SQL> alter session set SQL_TRACE=false; 
设置当前系统的 SQL_TRACE 
SQL> alter system set SQL_TRACE=true; 
对其他用户进行跟踪设置:
SQL> select sid,serial#,username from v$session where username='XXX';
       SID    SERIAL# USERNAME
    ------ ---------- ------------------
       127      31923 A
       128      54521 B
       129      48940 B
SQL> exec dbms_system.set_SQL_TRACE_in_session(127,31923,true);
SQL> select * from dual;
SQL> exec dbms_system.set_SQL_TRACE_in_session(127,31923,false); 
然后使用oracle自带的tkprof命令行工具格式化跟踪文件。
使用10046事件进行查询:
10046事件级别:
Lv1  - 启用标准的SQL_TRACE功能,等价于SQL_TRACE
Lv4  - Level 1 + 绑定值(bind values)
Lv8  - Level 1 + 等待事件跟踪
Lv12 - Level 1 + Level 4 + Level 8
全局设定:
..OracleHome/admin/SID/pfile中指定: EVENT="10046 trace name context forever,level 12" 
当前session设定:
SQL> alter session set events '10046 trace name context forever, level 8';
SQL> select * from dual;
SQL> alter session set events '10046 trace name context off'; 
对其他用户进行设置:
SQL> select sid,serial#,username from v$session where username='XXX';
       SID    SERIAL# USERNAME
    ------ ---------- ------------------
       127      31923 A
       128      54521 B
       129      48940 B    
SQL> exec dbms_system.set_ev(127,31923,10046,8,'A');
SQL> select * from dual;
SQL> exec dbms_system.set_ev(127,31923,10046,0,'A'); 
注意:常用的查看执行计划方法为 autotrace和explain plan for。通过设置sql_trace和10046事件来查看执行计划的情况较少 
注:无法使用autotrace的解决办法(9i): 
SQL>start $ORACLE_HOME/rdbms/admin/utlxplan.sql;
SQL>create public synonym plan_table for plan_table;
SQL>grant ALL on plan_table to public;

如何读懂执行计划
创建实验环境如下
SQL> create table t1(id int,name varchar2(500));
Table created.
SQL>  create table t2(id int,name varchar2(500));
Table created.
SQL> create index ind_t1 on t1(id);
Index created.
SQL>  create index ind_t2 on t2(id);
Index created.
SQL> create index ind_t2_name on t2(name);
Index created.
SQL> insert into t1 select object_id,object_name from dba_objects;
50430 rows created.
SQL> exec dbms_stats.gather_table_stats('HR','T1',cascade=>true,method_opt=>'for all indexed columns');
PL/SQL procedure successfully completed.
SQL> set autotrace trace explain 
执行如下查询
SQL> select * from t1 where id in (select ID FROM t2 where name='AA')
Execution Plan
----------------------------------------------------------
Plan hash value: 3232435503
--------------------------------------------------------------------------------------
| Id  | Operation                   | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |        |     1 |   293 |     5  (20)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T1     |     1 |    28 |     2   (0)| 00:00:01 |
|   2 |   NESTED LOOPS              |        |     1 |   293 |     5  (20)| 00:00:01 |
|   3 |    SORT UNIQUE              |        |     1 |   265 |     2   (0)| 00:00:01 |
|*  4 |     TABLE ACCESS FULL       | T2     |     1 |   265 |     2   (0)| 00:00:01 |
|*  5 |    INDEX RANGE SCAN         | IND_T1 |     1 |       |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   4 - filter("NAME"='AA')
   5 - access("ID"="ID")
Note
-----
   - dynamic sampling used for this statement 
以上执行计划中各列的意义如下
ID:序号,注意,ID的到小并不代表执行的先后顺序
Operation:当前的操作内容
Rows列:当前操作的cardinality(9i),Oracle估算当前操作的返回结果集的行数,这个行源可能是一个表,一个索引,也可能是一个子查询。
Bytes:操作的数据量大小
Cost(cpu):Oracle计算出来的一个数值(代价),用于说明SQL执行的代价。
Time:Oracle估算当前操作所需的时间。
执行计划中缩进度越大,表示越早执行,当两行的缩进一样时,最上面的最先被执行。上面的执行计划需从 缩进度 最大的行读取,他是最先执行的步骤。具体过程为: ID4->ID3->ID5->ID2->ID1->ID0
翻译成文字如下: 
在t2表中根据name=AA查找匹配的行,找出所有行并排序后与t1表上的索引ID_1中相应的ID进行关联,然后重复,直到把排序的结果集扫描完,这 个过程叫做nested loops。当整个T2表扫描完后,会产生一个结果集,这个结果集是IND_T1的一个索引结果集。然后Oracle根据索引键值上的rowid去T1表 中找相应的记录,即ID1.然后返回结果,即ID0。
上面的filter和access都是按照谓词的条件对数据进行过滤的方式,他们的区别如下:
filter,表示谓词条件的值并不会影响数据访问路径,只起到过滤的作用。
access,表示谓词条件的值会影响数据的访问路径(表还是索引,这里是索引)。
结果集Rows对执行计划的影响 
当前操作的rows(9i中为cardinality,10g替换为rows)表示Oracle估算当 前操作的返回结果集的行数,这个行源可能是一个表,一个索引,也可能是一个子查询。rows表示CBO估算当前操作预期获取的记录数,这个值对CBO做出 正确的执行计划至关重要。如果CBO获得的rows不准确(通常是没有做分析或者分析数据过旧导致的),在执行成本计算上会出现偏差,从而导致CBO产生 错误的出执行计划 。具体可参加下列例子
SQL> create table t as select 1 id,object_name from dba_objects;
Table created.
SQL> update t set id=99 where rownum=1;
1 row updated. 
SQL> commit;
Commit complete.
SQL> create index t_ind on t(id);
Index created.
采用dynamic_sampling(t 0)的方式禁止对t表的动态采用。 
SQL> select /*+ dynamic_sampling(t 0) */ * from t where id=1;
Execution Plan
----------------------------------------------------------
Plan hash value: 1376202287
-------------------------------------------------------------------------------------
| Id  | Operation                   | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |       |   194 | 15326 |    50   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T     |   194 | 15326 |    50   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | T_IND |    77 |       |    49   (0)| 00:00:01 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("ID"=1) 
可以看到CBO猜测ID为1的数据有194条,相对于总数来说较少,故采用了索引而不是全表扫描。
SQL> select * from t where id=1;
Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      | 47242 |  3644K|    56   (4)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T    | 47242 |  3644K|    56   (4)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("ID"=1)
Note
-----
   - dynamic sampling used for this statement 
上面的查询中,CBO通过动态采用,估算出表中的实际数据量为47242,非常接近实际数据量50249,故采用了全表扫描。
可见,rows的多少直接影响了执行计划的选择
在多表关联查询或者SQL中有自查询时,每个关联表或是自查询的rows对主表的影响非常大,甚至可以说,CBO就是依赖于各个关联表或者子查询rows值来计算出最后的执行计划。
对于多表查询,CBO使用每个关联表返回的行数决定使用什么样的访问方式来做关联(比如nested loops join或是hash join);对于子查询,它的rows将决定子查询是使用索引还是使用全表扫描的方式访问数据。
实验步骤如下
采用cardinality(t2 1000)的方式告诉CBO从T2表中获取10000条记录;
SQL>select * from t1 where id in (select  /*+ dynamic_sampling(t2 0) cardinality(t2 10000) */ id from t2 where name='AA')
Execution Plan
----------------------------------------------------------
Plan hash value: 2007208103
----------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name        | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |             | 50430 |    14M|       |   288   (2)| 00:00:04 |
|*  1 |  HASH JOIN SEMI              |             | 50430 |    14M|  1976K|   288   (2)| 00:00:04 |
|   2 |   TABLE ACCESS FULL          | T1          | 50430 |  1378K|       |    56   (2)| 00:00:01 |
|   3 |   TABLE ACCESS BY INDEX ROWID| T2          | 10000 |  2587K|       |     1   (0)| 00:00:01 |
|*  4 |    INDEX RANGE SCAN          | IND_T2_NAME |     1 |       |       |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - access("ID"="ID")
   4 - access("NAME"='AA') 
通过 cardinality(t2 1000)的方式模拟出了子查询中返回的结果集数,因此生成执行计划时,CBO选择了HASH JOIN SEMI。 
当结果集变小时执行计划如下
SQL> select * from t1 where id in (select /*+ dynamic_sampling(t2 0) cardinality(t2 1) */ id from t2 where name='AA') 
Execution Plan
----------------------------------------------------------
Plan hash value: 2850018061
----------------------------------------------------------------------------------------------
| Id  | Operation                      | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |             |     1 |   293 |     4  (25)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID   | T1          |     1 |    28 |     2   (0)| 00:00:01 |
|   2 |   NESTED LOOPS                 |             |     1 |   293 |     4  (25)| 00:00:01 |
|   3 |    SORT UNIQUE                 |             |     1 |   265 |     1   (0)| 00:00:01 |
|   4 |     TABLE ACCESS BY INDEX ROWID| T2          |     1 |   265 |     1   (0)| 00:00:01 |
|*  5 |      INDEX RANGE SCAN          | IND_T2_NAME |     1 |       |     1   (0)| 00:00:01 |
|*  6 |    INDEX RANGE SCAN            | IND_T1      |     1 |       |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   5 - access("NAME"='AA')
   6 - access("ID"="ID") 
可以看到因为子查询的结果集为1,所以CBO选择了netsted loops的方式进行关联。
两表关联的执行计划结果与上面类似,读者可根据如下语句自行进行实验,笔者在此也不再赘述。
select /*+ dynamic_sampling(t2 10000) cardinality */ * from t1,t2 where t1.id=t2.id;
select /*+ dynamic_sampling(t2 1) cardinality */ * from t1,t2 where t1.id=t2.id; 
以上的例子主要说明了rows对CBO生成执行计划的影响,在看执行计划时要特别关注。一定要注意每个操作的rows值,如果这个值明显不对,那么很可能操作的表的分析数据出了问题或者表没有分析。
DDL的执行计划 
从Oracle10g开始,可以通过EXPLAIN PLAN FOR查看DDL语句的执行计划了。
在9i及以前版本,Oracle只能看到DML的执行计划,不过从10g开始,通过EXPLAIN PLAN FOR的方式,已经可以看到DDL语句的执行计划了。
这对于研究CREATE TABLE AS SELECT、CREATE MATERIALIZED VIEW AS SELECT以及CREATE INDEX,ALTER INDEX REBUILD等语句有很大的帮助。
举个简单的例子,Oracle的文档上对于索引的建立有如下描述:
The optimizer can use an existing index to build another index. This results in a much faster index build.
如果看不到DDL的执行计划,只能根据执行时间的长短去猜测Oracle的具体执行计划,但这种方法没有足够的说服力。但是通过DDL的执行计划,就使得结果一目了然了。下面就来验证下 Oracle文档上的说法 
SQL> create table t_ddl as select * from dba_objects;
Table created.
SQL> explain plan for create index t_ddl_idx on t_ddl(object_name);
Explained.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 1333762510
------------------------------------------------------------------------------------
| Id  | Operation              | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | CREATE INDEX STATEMENT |           | 58238 |  3753K|   297   (1)| 00:00:04 |
|   1 |  INDEX BUILD NON UNIQUE| T_DDL_IDX |       |       |            |          |
|   2 |   SORT CREATE INDEX    |           | 58238 |  3753K|            |          |
|   3 |    TABLE ACCESS FULL   | T_DDL     | 58238 |  3753K|   160   (2)| 00:00:02 |
------------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Note
-----
   - estimated index size: 5242K bytes
14 rows selected.
SQL> create index t_owner_name on t_ddl(owner,object_name);
Index created.
SQL> explain plan for create index t_name on t_ddl(object_name);
Explained.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2111373224
---------------------------------------------------------------------------------------
| Id  | Operation              | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | CREATE INDEX STATEMENT |              | 58238 |  3753K|   297   (1)| 00:00:04 |
|   1 |  INDEX BUILD NON UNIQUE| T_NAME       |       |       |            |          |
|   2 |   SORT CREATE INDEX    |              | 58238 |  3753K|            |          |
|   3 |    INDEX FAST FULL SCAN| T_OWNER_NAME |       |       |            |          |
---------------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Note
-----
   - estimated index size: 5242K bytes
14 rows selected.
可以看到,根据现有的创建索引创建索引的速度确实会更快。笔者个认为,对于DDL的执行计划,最有价值的是在进行DDL操作前的开销评估。 
SQL> SET AUTOT ON
SQL> CREATE INDEX IND_T_NAME ON T(OBJECT_NAME); 
Index created. 
注意,查看DDL的执行计划需要使用EXPLAIN PLAN FOR,AUTOTRACE对于DDL是无效的。 

 

参考至:《让Oracle跑得更快》谭怀远著
            http://blog.csdn.net/zhoubo200/article/details/5345019
            http://wenku.baidu.com/view/c687e7325a8102d276a22fe7.html
            http://blog.csdn.net/tianlesoftware/article/details/5827245
            http://www.cnblogs.com/kelin1314/archive/2009/12/08/1619414.html

本文原创,转载请注明出处、作者
如有错误,欢迎指正

邮箱:czmcj@163.com



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


ITeye推荐



大二的学生想从事科学研究工作,但是感觉理论知识不够,同龄人都是怎么做到的?

$
0
0
很有意思的是,我现在就是一个国创计划的负责人。研究的东西恰好就是知乎,我们对知乎的“风格”很感兴趣,她真的很特别。(我肯定不会在百度知道做这些事情)

1.首先肯定你对所学的热诚,这一点非常重要!一个人只有真的对专业知识感兴趣,他才会去思考和研究,才会发问——正如你正在做的那样。鼓励一下,莫放弃好奇心。

2.其次说说我对大学生(包括我自己)做这个小东西的想法。
说实话,我是看到了一些人对大学生做研究的偏颇说法以后才抛下今晚的学习任务来写这些东西的。
项目从申报书开始。我发现,大学生,尤其理科生写东西的能力确实不怎么样。首先,我在社团里工作的时候,看到有挺多同学不会使用书面化的语言,有些连申请表格都填不好;其次,在写申报书的时候,我这个组是两三个同学一起写(恰好这个课题涉及到的几个板块),确实一开始我对我们的项目申报书上写的东西不是很有信心,也不知道“研究现状”是否真的就是那样,也不知道我们的可行性分析是否就如我们所说的那样“具有创新性”。但我们几人改了好几次申报书(不下三次),在用词和安排整个申报书的结构上,甚至还跟队友发生争执和矛盾,最后才定稿。(交申报书之前还发现了几处打印的错误> <)回想起来,我觉得大家的idea或许会大同小异,但真正落到实处,写出来的东西差别却很大:
申报书的质量高低往往决定了课题级别
最后我们挺意外地拿到国家级资助。我不知道大家怎么看申报书这个事情,很多时候,申报书的质量就可以看出这个团队能力。
团队管理是非常考验人的。我这个组最初有5个同学,一个学期过后只剩下现在3个人;一路走来,虽然目前还没有做出实质性成果和突破,但三人的感情越来越好。我们互相学习(包括三块:社会网络分析+自然语言处理+信息抓取),具体地说, 我希望我们经过这一年的工作,可以学到课堂上学不到的东西,这三个方面都懂,且尽可能熟悉某一块。这是我的理念。虽然学生做事情执行力不高,但我发现,其实并不是我的队友不给力,而是我不够主动——如果我push他们做事,事情很快就能做好。正如我们用了一周就解决了抓取的问题(我们以Scrapy为基础开发了爬虫),而且这个过程让队伍的士气得到提振。
但是,我一开始的时候,根本就不知道要怎样管理项目和团队。尤其是团队里没有权威的时候。老师这样说:
一个项目,三个人做是最好的。那些五六个人的,到后面往往都撒手
在参与团队工作的过程中,不论是项目负责人,还是团队成员,都是对自己日后工作能力的考验。这句话一定不会有错, 我们怎么可能成为一个好的team player而没有亲身体会过、扮演过“团队成员”这个角色呢?
在我看来,学生团队中的Team Leader根本就不是什么。真的
大学生做科研的质量。这一块可能被别很多人拿出来说大学生搞科研就是个屁对吧?确实,我先明确:
我们做的不是科研,我们是做探究。我们有一个疑问,然后我们用自己的所学和对事物的认知去解释这个东西,并希望可以搏看我们文章的人一笑。
我是学数学的,我十分仰慕那些做纯数学的人。要知道,这些工作的周期可能非常长,而且你做出来的东西可能没多少人会关注(或者说你死后才有人发现它的价值)。 我对“科研”一词的敬仰,多过对女神的yy。所以:
那些不认同大学生做研究的人,请暂且收起质疑吧
说实话,我是在接触了这些东西以后才知道数学有多伟大。不只是神奇,是伟大!我完全无法想像“文本相似度”可以那样简单而初等地计算,我被那些基于统计原理的“分词”方法迷倒,我甚至被算法的美偷走了我对女神的倾慕。
我现在只对数学和编程感兴趣
回到正题。单从发文数量和质量上看,大学生科研训练的产出确实不高。但就在我的学校,广东某211,物理和化学学院的学生就很强,他们以第一作者身份发不错的文章的人数还不少。我的意思是,每年我们学校的国家级队伍就那么几十支,有5~6支队伍可以有很棒的成果。(“很棒”是指本科生中比较突出)这个比例还是可以的了!我的意思是,我们没法要求每个人都上清华北大,对么?这个概率算还可以了吧?
如果有人说本科生发论文都很水,但我想知道,如果没有人这么做?那些博导怎么去招PhD?只有做过的人才有发言权,真的。

至于我们项目的质量,说实在话,我的导师很nice,他带我们去公司与业界人士聊天;老师把他认识的做搜索的公司人的联系方式给我们,老师每周都会跟进我们的项目进度(我都不好意思说我们的进度跟不上了)但是老师很细心,我能明白他想尽一切办法为我们提供资源和帮助。更多的是方法论上的,老师说过的一些话我还记得:
  • 为什么前人不这样做?是条件不允许,还是这样的意义不大?如果你们可以做,你觉得你的意义在哪里?
  • 有些东西是到哲学层次的了。你们做好基础性工作,努力完成它!


恬不知耻地,说说我们的“成果”吧。我自己都呵呵了,求鼓励和帮助!
  1. 我们绘制了某个话题板块的部分精华帖所形成的网络图。

    我们想从中找出那些experts,看这些用户是否可以带动知乎的其他用户。
  2. 我们想知道,人是怎样决定给一个回答点“赞同”的。要知道,有些开放性的话题,如果用文本相似度来排序,肯定会是ridiculous的;但从语义或者文本分析上来说,该怎么判断呢?
  3. 你我都逐渐发现,知乎不是那么简单的知识分享,她还是一个知识库!如果可以量化一个文章/帖子的质量的话,要怎么做?

(在这里真心请教大家,希望可以给点意见;因为我发现 很多东西不是我们不懂,而是我们不知道有某样东西可以做

3. 最后,科研训练带给我们什么?
我以前会功利地思考问题,功利地去“搞科研”(在审查之前加班赶工,水水地交差完事)因为我觉得这些可能对我的申请有帮助。
但现在,我明白有些东西,特别是学习,往往是水到渠成的。我发现,我们正在做的、涉及的知识和技术,它非常有意思。我们在Coursera上跟Social Network Analysis,我们到GitHub上找开源的分词工具,自己看着别人写的教程一点点地写爬虫。现在,我对这三块都有了解(但遗憾的是目前还不精通),我对这些话题越来越有兴趣,思路越来越清晰(终于有了研究方向)

我甚至把我们的东西放到了GitHub, zihaolucky/Undergraduate-Innovation-Program · GitHub 因为我实在仰慕和欣赏程序员这个群体。我认为再没有任何哪个群体能如他们那样热爱技术,而且热爱与人交流,热爱开源!我提出把东西放到GitHub上,一方面是为了方便管理;更重要的,其实是我希望我们团队的同学可以明白:
做再有料的产品,别人不知道也没用。
我们可以写更好的文档,帮助解决那些我们也曾困扰过的问题。
推销自己!
我做这些东西,甚至找到了自己今后想要去的实习公司。(现在自己能力还不够,所以一直忍着没有把简历投过去;这种煎熬会让我加快学习进度)我受益很多!


LZ你看,我虽然没有什么成果,但可以写这么多东西。我是怎么做到的?其实我也不知道,做了就知道了。

最后还是卖卖广告,我们真的很想得到一些帮助。尤其是我,我负责自然语言处理这块,目前进展很少,希望得到你们的指点:zihaolucky at gmail dot com

今天在weibo上看到上海交大老师写的关于本科生科研能力培养的文章: http://www.cs.sjtu.edu.cn/~liwujun/paper/ugresearch_cccf.pdf



==============更新====================
得到大家的帮助,很受感动。刚才恰好看了大家对知乎的感情,以及对知乎她身上正在发生的变化;我想,能写这些的都是爱知乎的。或者说,都是热爱真理,心存包容的。

我重新审视了一下自己的言行,发觉还是有很多地方不很成熟。不过,在交流和包容的机制下,我相信大家会随着知乎一起成长和进步。




物理与电信工程学院本科生在国际权威刊物上发表学术论文
华南师范大学

— 完 —
本文作者: 郑梓豪

【知乎日报】 你都看到这啦,快来点我嘛 Σ(▼□▼メ)

此问题还有 46 个回答,查看全部。
延伸阅读:
作为非物理专业的学生,量子物理大学课程应该如何学?若要学习量子物理,还应该有哪些知识基础?
人文学科最有效的学习途径是什么?

两款互联网登录系统曝出重大漏洞 短期内或无法修复

$
0
0

几周前,OpenSSL网站加密工具曝出的“Heartbleed”漏洞,已经将整个互联网安全领域震翻了一回。尽管绝大多数网站都在第一时间修复了它,但是一个新的问题又浮出了水面。一名安全研究人员发现了两款登录系统上的重大漏洞,而想要修复它们,却比Heartbleed要困难得多。

据Cnet报道,新加坡南洋理工大学一位名叫Wang Jing的博士生,发现了OAuth和OpenID开源登录工具的“隐蔽重定向”漏洞(Covert Redirect)。

这可导致攻击者创建一个使用真实站点地址的弹出式登录窗口——而不是使用一个假的域名——以引诱上网者输入他们的个人信息。

鉴于OAuth和OpenID被广泛用于各大公司——如微软、Facebook、Google、以及LinkedIn——Wang表示他已经向这些公司已经了汇报。

Wang声称,微软已经给出了答复,调查并证实该问题出在第三方系统,而不是该公司的自有站点。

Facebook也表示,“短期内仍无法完成完成这两个问题的修复工作,只得迫使每个应用程序平台采用白名单”。

至于Google,预计该公司会追踪OpenID的问题;而LinkedIn则声称它将很快在博客中说明这一问题。

讽刺的是,微软、Google、以及其它科技公司,在早几天才宣布了“资助开源安全系统研究,以避免又一个Heartbleed危机”的消息。

投资人最看好的3大创业方向

$
0
0

10年前在中国创业,只要做得像样都能赚到钱,而如今任何一个行业都弥漫着竞争的硝烟,想要出类拔萃很难。这样的定律同样适用于如今的投资界,虽然现在的机会越来越多,但VC/PE是一个周期长且由价值投资驱动的行业,更多时候所谓的投资方向得敏感于市场需要什么,据此快速调整。

在经历一轮疯狂、浮躁、喧嚣的调整后,迎来了后疯狂时代,眼下投资人究竟该投什么又一次成为了一个现实的问题。

医疗健康——投资界的常春藤

投资机会:

受人口老龄化、新医改政策的刺激等因素影响,医疗健康行业投资活跃度的逆市上涨显示出了这一抗周期性行业在经济下行期间的投资价值。

投资方向:

从细分领域来看,医疗器械和医疗健康连锁服务业是两个主要的方向。

投资分析:

进口替代的大趋势正在主导整个医疗器械行业的投资价值。何为进口替代?启明创投合伙人胡旭波以机构早期的投资项目奥泰医疗为例,其投资初衷是希望中国团队能做出一个顶级产品来打破进口垄断的局面。从2010年企业做出中国第一台超导5T的核磁共振,到开始被国内医院接受,并慢慢地促使产品质量差不多的GE、西门子、飞利浦这些高端产品把价格降下来,胡旭波说这就是一个进口替代的过程。“进口替代是很大的一个趋势,目前很多行业尤其是高端医疗行业,90%是进口,我相信这个数字会降到40%~50%,但前提是需要找到一个很强的团队来做出跟进口产品一样质量的产品。”

曾对医疗器械有过深入研究的奥博资本联合创始人王健认为未来这一细分市场在具体品类上也有颇多机会。“在医疗器械领域,比如涉及创伤修复方面的产品,国内企业已占据了国内大多数市场。但是像人工关节、脊柱这些产品还有很大的成长空间。”

此外,医疗健康涉及的连锁性的服务企业也越来越多地进入投资人的视野。达晨创投总经理屠铮曾考察过肿瘤类、美容类、齿科类等专科医院,他发现一些对医生或是昂贵的设备依赖比较低的医疗服务机构是个理想的投资标的。在他看来,这种容易复制且不需要太大投入的专业医院连锁未来催生的机会将更多。

TMT——互联网不只是一张网

投资机会:

高原资本执行董事姚亚平说,“未来互联网的投资机会不再是纯粹的互联网,纯粹的信息流,而是会越来越多地向每一个行业去延伸。”

投资方向:

如果要在TMT领域寻找其中的香饽饽,互联网及移动互联网必定首当其冲。

投资分析:

在腾讯投资执行董事林海峰看来,互联网是一场革命,这个革命的力度可以跟电力革命相媲美。“当电产生以后成为巨头的不仅仅是GE这样的发电公司,它还催生了一大批的行业。不管是做灯泡的,还是生产洗衣机、电视机等家用设备的公司。互联网也是同样的道理,它已覆盖人类每一个角落。”林海峰说。

不容置疑的是,在这一大前提下,以互联网的思维来寻找改变传统行业的投资思路几乎成为了业内共识。姚亚平把其看成是一个互联网领域的“存量市场”。所谓的“存量市场”指的是已经存在传统生意,但现在利用互联网的手段来提高交易效率,然后赚取利润。

姚亚平认为,这个“存量市场”是一门高速发展、高利润的生意,投资人越来越多的价值将是如何在被互联网改造的传统行业里寻找机会。他提到,机票、酒店是第一个被互联网改造的行业,接下来是通过团购改造的生活信息、生活服务业,之后是被互联网所改造的金融行业。

“每一个传统行业都会被互联网所改造,每一个被改造的都是互联网深入的一个机会。过去在‘增量市场’上谁跑得快谁就有优势。但在做‘存量市场’的投资里面,它是一个马拉松,谁能够最懂这个市场,谁能够建得起最深的壁垒谁就有价值。”

据他判断,以后互联网的创业价值在于是不是能用最快的时间建立起来比别人更深的壁垒,是不是有一个线下的“护城河”是BAT这几家做不了的。

节能环保——霾经济背后的技术支撑

投资机会:

PM2.5的频频爆表带来的商机不仅仅只是几只空气净化器那么简单。严重雾霾天所导致的环保政策的倾斜正在为VC/PE行业带来更多的投资机会。

投资方向:

虽然这个领域聚焦的细分投资机会每年的变化并不大,比如土壤修复、水治理、垃圾处理、新能源等等,但在这背后投资人看中的技术主线已愈发清晰。

投资分析:

凯旋创投创始人周志雄直言在这个领域,技术是一个关键的因素。他发现,国内企业对于技术有很大的需求,这其中一个讨巧的做法即是引进国外的先进技术。

他进一步解释道,海外的一些技术发展到一定阶段也面临挑战,比如像美国的一些技术制造成本太高,而这些技术在美国的用途没有像中国那么有需求。如果把它们引入中国来、,尤其是跟清洁及环境有关的技术,当中国的市场适合这种技术时就能在开拓市场时占得先机。

对于IDG资本合伙人俞信华来讲,他也相当看好技术的门槛。“我们更愿意投有壁垒的企业,就是说企业真的有技术,如果企业是做工程服务的,往往会受政策影响较大。而企业只有真正掌握核心的技术、关键的产品,才能保持持续的增长。”

同样的,国经基金副总经理邱翼每年也会接触上百项新的技术,从中选择心仪的投资标的。但他提醒到,现阶段这个技术在国内是不是适用是一个需要考虑的重点。“首先要评估它的经济技术的合理性,就是说技术可能很好,但是在现阶段可能不太适用。”他举例说,污水处理的水价如果是1元左右,但通过技术价格却要提升到了10元,那么企业的技术可能在现阶段就不适用了。一旦技术超前与市场承受能力脱轨,那就并非一个理想的投资项目。

google中关于网页标题和描述的说明

$
0
0

Google 生成网页标题和描述(或“摘要”)的过程是完全自动的,会同时考虑网页内容及网络上对此页的引用。使用网页摘要和标题是为了充分展现和描述每条结果,并说明结果与用户查询的相关程度。


您提供给我们的信息越多,您的搜索结果摘要就越精确。网站站长可以采用丰富网页摘要对网站的结构化内容(例如评论网站或商家信息等)进行标记,以此表明所标记的每段文字都代表一种特定类型的数据(例如餐馆名称、地址或评分等)。详细了解丰富网页摘要如何改进您的网站在搜索结果中的排列方式。

我们使用此信息的多个不同来源,其中包含每个网页标题和元标记中的描述性信息。我们还可能会使用公开的信息(例如,来自开放式目录管理系统 (DMOZ) 的定位文字或列表),或根据网页上的标记创建 丰富网页摘要。


尽管我们无法手动为各个网站更改标题或摘录,但我们一直致力于增强它们之间的相关性。您可按以下通用准则操作,以便改善您网页所显示的标题和摘要的质量。


创建描述性的网页标题

创建良好的元描述

阻止搜索引擎在搜索结果中显示有关您网站的 DMOZ 数据

创建描述性的网页标题


标题非常重要,它可以让用户快速了解结果的内容以及与其查询相关的原因。它常常是决定点击哪个结果的主要信息,因此在您的网页上使用高品质的标题非常重要。


下面是针对管理标题的一些提示:


如上所述,确保您网站上的每个网页都在 标记。


网页标题应具有描述性并且简明扼要。避免不明确的描述,例如对首页使用 "Home",或对某个人的个人资料使用 "Profile"。还要避免不必要的长标题或罗嗦的标题,因为这种标题显示在搜索结果中时可能会被截断。


避免关键字堆砌。在标题中包含几个描述性词汇有时会有帮助,但不能让相同的词或短语出现多次。像 "Foobar, foo bar, foobars, foo bars" 这样的标题对用户并没有帮助,而且此类关键字堆砌可能会导致 Google 和用户将您的结果视为垃圾内容。


避免重复或样板标题。您网站上的每一个网页都应该有独特的描述性标题。例如,将商业网站每个网页的标题都写成“便宜商品促销”就会导致用户无法区分各个网页。只有信息变化不大的长标题(“样板”标题)也不好,例如,像 " - See videos, lyrics, posters, albums, reviews and concerts" 这样的标准化标题就包含大量没有参考价值的文本。其中一种解决办法是动态更新标题,以更好地体现网页的实际内容:例如,只有在特定网页包含视频或歌词时才使用“视频”、“歌词”等词。另一种选择是仅使用 "" 作为简要标题,使用元描述(参见下文)来说明网站的内容。网站站长工具中的 HTML 建议网页列出了 Google 在您的网页上检测到的所有重复标题。


给您的标题加上品牌,但应简明扼要。您可以在自己网站的首页标题中加入一些关于您网站的其他信息,例如 "ExampleSocialSite, a place for people to meet and mingle."。 但是,在网站每个网页的标题中都显示该文字就会破坏可读性;如果对同一查询返回了您网站的多个网页,看起来就很罗嗦。在这种情况下,应考虑仅在每个网页标题的开头或结尾包含网站名称,用破折号、冒号或竖线等分隔符与标题的其余部分分隔开,类似这样:


请注意关于禁止搜索引擎抓取网页的问题。在您的网站上使用 robots.txt 协议可以阻止 Google 抓取网页,但不一定能阻止网页被编入索引。例如,如果 Google 通过其他网站上的链接发现了您的网页,可能就会将您的网页编入索引。为了在搜索结果中显示您的网页,Google 就需要显示某些类型的标题,但由于无法访问您网页的任何内容,因此会依赖页外内容,例如来自其他网站的定位文字(要完全阻止网址被编入索引,您可以使用元标记)。

如果检测到某条结果的标题存在上述问题之一,我们可能会尝试根据定位文字、页面文字或其他来源生成经过改进的标题。但是,有时即使网页拥有结构良好且简明扼要的描述性标题,我们的搜索结果最终也会使用其他标题以更好地指明它与查询的相关程度。导致这种情况的原因很简单,那就是网站站长指定的标题标记被限制为静态固定标记,与查询无关。一旦我们收到用户的查询,我们常常可以从网页找到更好更相关的其他文字结果。使用这些文字作为标题对用户有帮助,对您的网站也有帮助。用户会在结果中搜索他们的查询词汇或其他相关性标志,而一个更贴近查询内容的标题可以提高用户点击率。


如果您看到自己的网页出现在搜索结果中但标题已被修改,请检查您的标题是否存在上述问题之一。如果没有,请考虑修改后的标题是否更贴近查询内容。如果您仍然认为原始标题更好,那么请访问我们的网站站长帮助论坛告诉我们。


创建良好的元描述


标记中的描述属性是为每个网页的内容提供简要易懂摘要的好方法。如果我们认为网页的元描述与完全来自页面内容的描述相比,可以向用户提供更准确的描述,Google 有时会在搜索结果摘要中使用元描述。准确的元描述可以帮助提高点击次数,下面是正确使用元描述的一些指南。


确保网站上的每个网页都有元描述。在网站站长工具中的 HTML 问题提示网页上,系统会列出 Google 发现其中缺少元描述或元描述存在问题的网页。


为不同网页创建不同的描述 。当各个网页都出现在网页搜索结果中时,在网站的每个网页上使用相同或类似的描述效果并不理想。在这些情况下,我们很少会显示样板化的文字。在可能的情况下,请尽量创建能够准确概括特定网页的描述。在首页或其他汇总页上使用网站一级的描述,在所有其他网页上使用网页一级的描述。如果您没有时间为每个网页创建描述,请尝试为您的内容划分优先等级:至少为关键的网址(例如,首页和受欢迎的网页)创建描述。


在描述中加入清楚标记的信息。 元描述不仅限于句子的形式,也可以包含有关网页的结构化数据。例如,资讯或博客帖子可以列出作者、发布日期或副线信息。这可为潜在访问者提供相关度非常高的信息,如果没有这些数据,摘录中就不会显示这些信息。同样,产品页也可能包含一些遍布整个网页的重要信息片段,如价格、生产日期、制造商等。良好的元描述可将所有这些数据汇总在一起。

例如,下列元描述提供了有关某书籍的详细信息。

插图:江阳, 类别:图书, 定价:¥25.00, 

页数:784 页">

在本例中,信息被清楚地标记并分开。以程序方式生成描述。 对于某些网站,例如资讯媒体来源,可以很方便地为每一个网页生成准确且独特的描述:由于每篇文章都是手写而成,因此添加单句描述非常容易。对于较大型的由数据库驱动的网站,例如产品汇总网站,无法完成手写描述。不过,程序生成的描述可能适合于后者,因此建议您采用。如上面第一点所述,良好的描述应当是用户可以阅读的,并且不能千篇一律。我们在第二点中提到的针对网页的数据非常适合在利用程序生成描述时使用。请注意,包含很多长串关键字的元描述不会使用户对网页内容产生清楚的印象,也不太可能代替常规摘录显示。


使用高质量的描述。 最后,确保您的描述确实具有描述性。由于元描述不会显示在用户查看的网页中,因此它的内容很容易被忽视。不过,高质量的描述会显示在 Google 的搜索结果中,因而可以大大提高您搜索流量的质量和数量。

阻止搜索引擎在搜索结果中显示有关您网站的 DMOZ 数据


Google 用来生成网页摘要的一个来源为开放式目录管理系统。您可以通过在网页中添加元标记来告诉我们不要使用此来源。


为防止所有支持元标记的搜索引擎使用此信息生成网页描述,请使用下列元标记:


要特别防止 Google 使用此信息生成网页描述,请使用下列元标记:


如果您使用漫游器元标记提供其他说明,可以结合使用这些元标记。例如:


请注意,将此元标记添加到网页中后,可能需要一段时间才会在索引中反映摘录更改。


如果您担心标题或摘录内容出现问题,可能需要确认该内容未出现在您的网站上。如果出现了,则更改此内容将会在我们下次抓取您的网站时影响您的 Google 摘录。如果没有出现,请在 Google.cn 上搜索标题或摘要,并将搜索内容括在引号中。这样会显示网络上通过此文本引用您网站的网页。如果您与这些网页的网站站长联系,请求他们更改有关您网站的信息,那么在下次抓取这些网页时,我们的抓取工具会识别所有更改。




  青春就应该这样绽放   游戏测试:三国时期谁是你最好的兄弟!!   你不得不信的星座秘密
Viewing all 15845 articles
Browse latest View live


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