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

jmap转换gcore的dump文件

$
0
0

找java进程

 

ps aux|grep java

yyy    4990  0.3  2.3 3098560 191312 ?      Sl   Aug29  16:11 /usr/xxx/jdk1.6.0_29/bin/java -Xms128m -Xmx768m -jar /usr/share/projectlibre/projectlibre.jar --silentlyFail true

 

 

使用gdb生成gcore快照文件

 

sudo gdb -q --pid=4990
【此处省略乱七八糟的输出内容】
......
0x00007ffc1672366b in pthread_join (threadid=140720663160576, thread_return=0x7fffe8470210) at pthread_join.c:92
92	pthread_join.c: No such file or directory.
(gdb) generate-core-file 
warning: target file /proc/4990/cmdline contained unexpected null characters
Saved corefile core.4990
(gdb) detach 
Detaching from program: /usr/xxx/jdk1.6.0_29/bin/java, process 4990
(gdb) quit

 

命令解释:
gdb -q --pid=4990
 
--pid后面跟着的是jvm的进程id
(gdb) generate-core-file 
 
这里调用命令生成gcore的dump文件
(gdb) detach 
 
detach是用来断开与jvm的连接的
(gdb) quit
 

quit简单了,退出gdb模式

用jmap转换gcore的dump文件变成hprof

sudo /usr/xxx/jdk1.6.0_29/bin/jmap -dump:format=b,file=heap.hprof /usr/xxx/jdk1.6.0_29/bin/java core.4990
Attaching to core core.4990 from executable /usr/xxx/jdk1.6.0_29/bin/java, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 20.4-b02
Dumping heap to heap.hprof ...
Finding object size using Printezis bits and skipping over...
Heap dump file created

 

 

接着就生成了heap.hprof这个文件

 

注意:jmap、java等指令必须是与启动4990进程一致的版本才可以成功转换,否则还是会有问题。

 

可以使用jvisualvm打开 heap.hprof查看jvm的快照信息。

 

参考文章:

  1. http://www.tuicool.com/articles/JbyyUr
  2. http://stackoverflow.com/questions/9981080/core-dump-taken-with-gcore-jmap-conversion-to-hprof-file-format-fails-with-erro
  3. http://blog.163.com/yandong_8212/blog/static/1321539142010108112559362/


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


ITeye推荐




全文检索的基本原理

$
0
0

一、总论

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

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

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

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

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

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

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

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

 

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

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

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

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

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

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

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

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

 

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

 

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



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

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

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

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

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

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

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

 

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

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

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

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

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

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

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

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



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

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

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

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

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

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

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



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

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

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

 

三、如何创建索引

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

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

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

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

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

 

第二步:将原文档传给分次组件(Tokenizer)。

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

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

2. 去除标点符号。

3. 去除停词(Stop word)

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

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

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

 

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

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

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

 

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

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

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

1. 变为小写(Lowercase)

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

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

 

Stemming 和 lemmatization的异同:

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

 

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

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

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

 

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

 

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

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

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

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

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

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

 

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

 

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



 
在此表中,有几个定义:

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

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

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

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

 

 

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

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

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

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



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

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

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

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

搜索主要分为以下几步:

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

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

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

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

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

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

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

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

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

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

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

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

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

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



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

如learned变成learn等。

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



 

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

此步骤有分几小步:

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

 

 

 

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

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

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

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

那么又怎么对文档之间的关系进行打分呢?

这可不是一件容易的事情,首先我们看一看判断人之间的关系吧。

首先看一个人,往往有很多 要素,如性格,信仰,爱好,衣着,高矮,胖瘦等等。

其次对于人与人之间的关系, 不同的要素重要性不同,性格,信仰,爱好可能重要些,衣着,高矮,胖瘦可能就不那么重要了,所以具有相同或相似性格,信仰,爱好的人比较容易成为好的朋友,然而衣着,高矮,胖瘦不同的人,也可以成为好的朋友。

因而判断人与人之间的关系, 首先要找出哪些要素对人与人之间的关系最重要,比如性格,信仰,爱好。 其次要判断两个人的这些要素之间的关系,比如一个人性格开朗,另一个人性格外向,一个人信仰佛教,另一个信仰上帝,一个人爱好打篮球,另一个爱好踢足球。我们发现,两个人在性格方面都很积极,信仰方面都很善良,爱好方面都爱运动,因而两个人关系应该会很好。

 

我们再来看看公司之间的关系吧。

首先看一个公司,有很多人组成,如总经理,经理,首席技术官,普通员工,保安,门卫等。

其次对于公司与公司之间的关系,不同的人重要性不同,总经理,经理,首席技术官可能更重要一些,普通员工,保安,门卫可能较不重要一点。所以如果两个公司总经理,经理,首席技术官之间关系比较好,两个公司容易有比较好的关系。然而一位普通员工就算与另一家公司的一位普通员工有血海深仇,怕也难影响两个公司之间的关系。

因而判断公司与公司之间的关系, 首先要找出哪些人对公司与公司之间的关系最重要,比如总经理,经理,首席技术官。 其次要判断这些人之间的关系,不如两家公司的总经理曾经是同学,经理是老乡,首席技术官曾是创业伙伴。我们发现,两家公司无论总经理,经理,首席技术官,关系都很好,因而两家公司关系应该会很好。

 

分析了两种关系,下面看一下 如何判断文档之间的关系了。

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

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

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

 

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

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

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

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

 

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

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

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

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

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

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

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



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

 

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

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

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

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

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

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

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

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

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

如图:



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

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

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

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

 

相关性打分公式如下:



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

 

t1

t2

t3

t4

t5

t6

t7

t8

t9

t10

t11

D1

0

0

.477

0

.477

.176

0

0

0

.176

0

D2

0

.176

0

.477

0

0

0

0

.954

0

.176

D3

0

.176

0

0

0

.176

0

0

0

.176

.176

Q

0

0

0

0

0

.176

0

0

.477

0

.176

 

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



 

 

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

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

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

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

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



  1. 索引过程:

1) 有一系列被索引文件

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

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

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

2. 搜索过程:

a) 用户输入查询语句。

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

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

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

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

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

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

下面我们可以进入Lucene的世界了。

另: 

CSDN中此文章链接为 http://blog.csdn.net/forfuture1978/archive/2009/10/22/4711308.aspx

Javaeye中此文章链接为 http://forfuture1978.javaeye.com/blog/546771 



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


ITeye推荐



来说说Java中的实例初始化器

$
0
0

文首先给出个例子来探究下什么是 实例变量初始化器,什么是 实例初始化器,以及什么是 静态初始化器。然后看看实例初始化器是怎么工作的。

1. 执行的顺序

先看看下面这段代码,你觉着哪部分会先被执行呢?

public class Foo {
    //instance variable initializer 实例变量初始化器
    String s = "abc";
    //constructor 构造函数
    public Foo() {
        System.out.println("constructor called");
    }
    //static initializer   静态初始化器
    static {
        System.out.println("static initializer called");
    }
    //instance initializer 实例变量初始化器
    {
        System.out.println("instance initializer called");
    }
    public static void main(String[] args) {
        new Foo();
        new Foo();
    }
}

输出如下:

static initializer called
instance initializer called
constructor called
instance initializer called
constructor called

2. Java的实例初始化器是如何工作的?

上面的例子中的实例初始化器包含一段打印字符的代码。要理解它是如何工作的,我们可以把它想象成变量赋值的过程,这样就不难理解了。

除了这么赋值:

int b = 0;

还可以这么写:

int b;
b = 0;

因此,实例初始化器和实例变量初始化器就大同小异了。

3. 什么时候会用到实例初始化器?

能用到实力初始化器的时候比较少。但有些时候还是一个实例变量初始化器的替代选择,比如:

  • 初始化代码必须处理异常情况
  • 执行一个实例变量没办法进行的计算

当然,这些需求还是可以在构造函数中实现的。但是一个类有多个构造函数的话,你就得在每个构造函数里面重复同样的代码了。

写在实例初始化器中的代码,无论你使用哪一个构造函数,实例初始化器中代码都会被执行(可能说的多,用的少吧)。

另一个实例初始化器的应用场景是匿名内部类,因为这种情况下根本就不能创建构造函数。(这可能是放置日志代码的好地方?)

参考: Java的初始化
首发: strongme

相关文章

index rebuild和rebuild online的区别

$
0
0

       曾经看到过淘宝的这个面试题:在一个24*7的应用上,需要把一个访问量很大的1000万以上数据级别的表的普通索引(a,b)修改成唯一约束(a,b,c),你一般会选择怎么做,请说出具体的操作步骤与语句。

       先online建索引添加约束,然后删除原理的索引。

       create index idx_test_abc on w_1 (a,b,c) online ;
       alter table test add constraint uni1 unique (a,b,c) novalidate; 
       drop index ;

       为什么要用online呢?原理是什么?

       1. rebuild 会阻塞dml语句而rebuild online则不会。

       2. rebuild online时系统会产生一个SYS_JOURNAL_xxx的IOT类型的系统临时日志表,所有rebuild online时索引的变化都记录在这个表中,当新的索引创建完成后,把这个表的记录维护到新的索引中去,然后drop掉旧的索引,rebuild online就完成了,类似于物化视图。

作者:guogang83 发表于2014-9-1 15:29:42 原文链接
阅读:3 评论:0 查看评论

Mongodb集群搭建过程及常见错误 - 翟中龙

$
0
0
Replica Sets
MongoDB 支持在多个机器中通过异步复制达到故障转移和实现冗余。多机器中同一时刻只 有一台是用于写操作。正是由于这个情况,为 MongoDB 提供了数据一致性的保障。担当 Primary 角色的机器能把读操作分发给 slave。
Replica Sets的结构非常类似一个集群。因 为它确实跟集群实现的作用是一样的, 其中一个节点如果出现故障, 其它节点马上会将业务接过来而无须停机操作。
下面以本机为例介绍一下集群的部署过程,以及部署过程中常见的注意点及错误
本例环境是Linux操作系统,mongodb版本:mongodb-linux-x86_64-2.6.1.tgz,Vmwre虚拟机,虚拟机IP:192.168.169.129,集群以本机不同端口模拟三台服务器。
1.集群主要分为三个节点master主节点,slaver备用节点,arbiter仲裁节点
建立数据文件夹
mkdir -p /mongodb/data/master
mkdir -p /mongodb/data/slaver
mkdir -p /mongodb/data/arbiter

 

ps:三个目录分别对应主,备,仲裁节点
2.建立配置文件夹
1)master.conf
    打开编辑器:
vi /etc/master.conf

按i 输入下列配置

dbpath=/home/mongodb/data/master
logpath=/home/mongodb/log/master.log
logappend=true
replSet=rep1
port=10000
fork=true
journal=true

完成之后按esc  》》 :  >>wq>>回车

2)slaver.conf
编辑器打开和保存按上边的步骤,下边只写详细内容
dbpath=/home/mongodb/data/slaver
logpath=/home/mongodb/log/slaver.log
logappend=true
replSet=rep1
port=10001
fork=true
journal=true

3)arbiter.conf

dbpath=/home/mongodb/data/arbiter
logpath=/home/mongodb/log/arbiter.log
logappend=true
replSet=rep1
port=10002
fork=true
journal=true
smallfiles=true

参数解释:

dbpath:数据存放目录

logpath:日志存放路径

logappend:以追加的方式记录日志

replSet:replica set的名字

port:mongodb进程所使用的端口号,默认为27017

fork:以后台方式运行进程

journal:写日志

smallfiles:当提示空间不够时添加此参数

其他参数

pidfilepath:进程文件,方便停止mongodb

directoryperdb:为每一个数据库按照数据库名建立文件夹存放

bind_ip:mongodb所绑定的ip地址

oplogSize:mongodb操作日志文件的最大大小。单位为Mb,默认为硬盘剩余空间的5%

noprealloc:不预先分配存储

3.启动Mongodb   

cd /home/mongodb/bin

 

启动服务

./mongod -f /etc/master.conf

./mongod -f /etc/slaver.conf

./mongod -f /etc/arbiter.conf

 有这样的提示说明启动成功

如果是下列的提示说明启动失败

启动失败的原因有很多,检查完配置文件,如果没有错误,可打开相应的配置文件查看详细的错误信息

cat /etc/master.conf

最常见的一个错误就是磁盘空间不足,会提示这样的错误

因为Mongodb的日志文件是成2g的增长,所以所需空间比较大,这时你可以在配置文件里添加这样的一个配置
smallfiles=true。
全部三个服务全部启动成功之后

4.配置主(master),备(slaver),仲裁(arbiter)节点

可以通过客户端连接mongodb,也可以直接在三个节点中选择一个连接mongodb。

./mongo 192.168.169.129:10000   #ip和port是某个节点的地址

>use admin

>cfg={ _id:"rep1", members:[ {_id:0,host:'192.168.169.129:10000',priority:2}, {_id:1,host:'192.168.169.129:10001',priority:1},
{_id:2,host:'192.168.169.129:10002',arbiterOnly:true}] };
>rs.initiate(cfg) #使配置生效
{
        "set" : "rep1",
        "date" : ISODate("2014-09-05T02:44:43Z"),
        "myState" : 1,
        "members" : [
                {
                        "_id" : 0,
                        "name" : "192.168.169.129:10000",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 200,
                        "optime" : Timestamp(1357285565000, 1),
                        "optimeDate" : ISODate("2013-01-04T07:46:05Z"),
                        "self" : true
                },
                {
                        "_id" : 1,
                        "name" : "192.168.169.129:10001",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 200,
                        "optime" : Timestamp(1357285565000, 1),
                        "optimeDate" : ISODate("2013-01-04T07:46:05Z"),
                        "lastHeartbeat" : ISODate("2013-01-05T02:44:42Z"),
                        "pingMs" : 0
                },
                {
                        "_id" : 2,
                        "name" : "192.168.169.129:10002",
                        "health" : 1,
                        "state" : 7,
                        "stateStr" : "ARBITER",
                        "uptime" : 200,
                        "lastHeartbeat" : ISODate("2013-01-05T02:44:42Z"),
                        "pingMs" : 0
                }
        ],
        "ok" : 1
}
 
配置过程中可能还会出现其他的一些错误,不过都可以去查看相应的日志文件,去解决。

本文链接: Mongodb集群搭建过程及常见错误,转载请注明。

angularJs 前端的页面分解与组装

$
0
0

实现前端页面的复用

将分解的页面写成directive. 例如下面这个样子:

angular.module('pageComponents', [], function($compileProvider){
  $compileProvider.directive('commonHeader', function($compile) {
    return {
      templateUrl: 'templete/common/common_header.html',
      replace: true,
      transclude: false,
      restrict: 'A',
      scope: false
    };
  });
  $compileProvider.directive('commonFooter', function($compile) {
    return {
      templateUrl: 'templete/common/common_footer.html',
      replace: true,
      transclude: false,
      restrict: 'A',
      scope: false
    };
  });
});

 事实上,还可以更进一步,将templateUrl写成可传入的参数。但是那样的话就跟下面这个方法差不多了。

 

使用ng-include非常简单。请注意src的参数是表达式,如果要传静态的字符串参数,请用引号将参数包裹起来。就像下面这个例子。

<!-- header --><ng-include src="'common_header.html'"></ng-include><div class="container"><!-- angular ng-view --><div ng-view></div><!-- /angular ng-view --></div><!-- Footer --><ng-include src="'common_footer.html'"></ng-include>

对ng-include稍作处理,可以实现更复杂的功能。例如下面这个动态加载表单页面的例子,就是通过变换ng-include的src参数实现的。

$compileProvider.directive("dynamicFormInput", ['$http', '$templateCache',
  function($http, $templateCache) {
    return {
      restrict : 'E',
      scope : {
        model : '=',
        section : '='
      },
      template : '<ng:include src="tpl"></ng:include>',
      link : function(scope, iElement, iAttrs) {
        switch(scope.section.sectionTypeId) {
          case 1:
            $http.get('partials/survey/textInput.html', {
              cache : $templateCache
            });
            scope.tpl = "partials/survey/textInput.html";
            break;
          case 2:
            $http.get('partials/survey/selectOneOption.html', {
              cache : $templateCache
            });
            scope.tpl = "partials/survey/selectOneOption.html";
            break;
          case 6:
            if (scope.section.sectionId == 19) {
              $http.get('partials/survey/addressSelection.html', {
                cache : $templateCache
              });
              scope.tpl = "partials/survey/addressSelection.html";
            }
            break;
        }
      }
    }
}]);

最后必须说明的是,这三种方法实质上都是利用ajax来加载模板。使用ajax来实现页面分解这样的功能,相比传统的使用后台动态脚本语言的方案,必然会 带来额外的开销。事实上,不光angularjs是这样,我所接触过的所有前端框架都是如此。这是浏览器端的宿命。这里所造成的负载和与后台动态脚本语言之间的优劣,只能由技术主管自己权衡。

 


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


ITeye推荐



Spring MVC Controller单例陷阱

$
0
0
Spring MVC Controller单例陷阱
2014-04-12 16:23:20
标签:Spring mvc
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://lavasoft.blog.51cto.com/62575/1394669
Spring MVC Controller默认是单例的:

单例的原因有二:
1、为了性能。
2、不需要多例。

1、这个不用废话了,单例不用每次都new,当然快了。
2、不需要实例会让很多人迷惑,因为spring mvc官方也没明确说不可以多例。
  我这里说不需要的原因是看开发者怎么用了,如果你给controller中定义很多的属性,那么单例肯定会出现竞争访问了。
  因此,只要controller中不定义属性,那么单例完全是安全的。下面给个例子说明下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.lavasoft.demo.web.controller.lsh.ch5;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* Created by Administrator on 14-4-9.
*
* @author leizhimin 14-4-9 上午10:55
*/
@Controller
@RequestMapping("/demo/lsh/ch5")
@Scope("prototype")
public class MultViewController {
    private static int st = 0;      //静态的
    private int index = 0;          //非静态
    @RequestMapping("/show")
    public String toShow(ModelMap model) {
        User user = new User();
        user.setUserName("testuname");
        user.setAge("23");
        model.put("user", user);
        return "/lsh/ch5/show";
    }
    @RequestMapping("/test")
    public String test() {
        System.out.println(st++ + " | " + index++);
        return "/lsh/ch5/test";
    }
}


0 | 0
1 | 1
2 | 2
3 | 3
4 | 4

改为单例的:
0 | 0
1 | 0
2 | 0
3 | 0
4 | 0

从此可见,单例是不安全的,会导致属性重复使用。

最佳实践:
1、不要在controller中定义成员变量。
2、万一必须要定义一个非静态成员变量时候,则通过注解@Scope("prototype"),将其设置为多例模式。

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


ITeye推荐



MySQL服务器端核心参数详解和优化建议整理

$
0
0
  原来的来自mysqlops网站的整理,摘录如下:
max_connect_errors
max_connect_errors默认值为10,也即mysqld线程没重新启动过,一台物理服务器只要连接
异常中断累计超过10次,就再也无法连接上mysqld服务,为此建议大家设置此值至少大于等于10W;
若异常中断累计超过参数设置的值,有二种解决办法,执行命令:FLUSH HOSTS;或者重新启动mysqld服务;
interactive_timeout and wait_timeout
interactive_timeout
处于交互状态连接的活动被服务器端强制关闭,而等待的时间,单位:秒;
wait_timeout
与服务器端无交互状态的连接,直到被服务器端强制关闭而等待的时间,此参数只对基于TCP/IP或基于
Socket通信协议建立的连接才有效,单位:秒;
推荐设置
interactive_timeout = 172800
wait_timeout = 172800


binlog-format
复制的模式,可供设置的值:STATEMENT、ROW、MIXED(注:5.0.*只有命令行式复制),
5.1.*版本默认设置:MIXED;
推荐配置
①只读为主的业务应用场景
transaction-isolation = read-committed
binlog-format = mixed #5.1.*版本,5.0.*只能设置为statement
①非只读为主的业务应用场景
transaction-isolation = repeatabled-read
binlog-format = mixed #5.1.*版本,5.0.*只能设置为statement


innodb_max_dirty_pages_pct
InnoDB主线程直接更新Innodb_buffer_pool_size中存在的数据,并且不实时刷回磁盘,而是等待
相关的处罚事件发生,则允许缓存空间的数据量不实时刷回磁盘的最大百分比。比例设置较小,有利于
减少mysqld服务出现问题的时候恢复时间,缺点则是需要更多的物理I/O,为此我们必须根据业务特点
和可承受范围进行一个折中,一般范围建议设置为5%~90%,像我们SNS游戏行业的写非常厉害,综合
各方面因素,推荐设置为20%;


innodb_commit_concurrency
含义:同一时刻,允许多少个线程同时提交InnoDB事务,默认值为0,范围0-1000。
0 ---允许任意数量的事务在同一时间点提交;
N>0 ---允许N个事务在同一时间点提交;
注意事项:
①mysqld提供服务时,不许把innodb_commit_concurrency 的值从0改为非0,或非0的值改为0;
②mysqld提供时,允许把innodb_commit_concurrency 的值N>0改为M,且M>0;
innodb_concurrency_tickets
含义:同一时刻,能访问InnoDB引擎数据的线程数,默认值为500,范围1-4294967295。
补充说明:当访问InnoDB引擎数据的线程数达到设置的上线,线程将会被放到队列中,等待其他线程
释放ticket。
建议:
MySQL数据库服务最大线程连接数参数max_connections,一般情况下都会设置在128-1024的范围,
再结合实际业务可能的最大事务并发度,innodb_concurrency_tickets保持默认值一般情况下足够。

innodb_fast_shutdown and innodb_force_recovery
innodb_fast_shutdown
含义:设置innodb引擎关闭的方式,默认值为:1,正常关闭的状态;
0 ---mysqld服务关闭前,先进行数据完全的清理和插入缓冲区的合并操作,若是脏数据较多或者服务器性能
等因素,会导致此过程需要数分钟或者更长时间;
1 ---正常关闭mysqld服务,针对innodb引擎不做任何其他的操作;
2 ---若是mysqld出现崩溃,立即刷事务日志到磁盘上并且冷关闭mysqld服务;没有提交的事务将会丢失,
但是再启动mysqld服务的时候会进行事务回滚恢复;
innodb_force_recovery
含义:mysqld服务出现崩溃之后,InnoDB引擎进行回滚的模式,默认值为0,可设置的值0~6;
提示:
只有在需要从错误状态的数据库进行数据备份时,才建议设置innodb_force_recovery的值大于0。
若是把此参数作为安全选项,也可以把参数的值设置大于0,防止InnoDB引擎的数据变更;
0 ---正常的关闭和启动,不会做任何强迫恢复操作;
1 ---跳过错误页,让mysqld服务继续运行。跳过错误索引记录和存储页,尝试用SELECT * INOT OUTFILE ‘../filename’ FROM tablename;方式,完成数据备份;
2 ---阻止InnoDB的主线程运行。清理操作时出现mysqld服务崩溃,则会阻止数据恢复操作;
3 ---恢复的时候,不进行事务回滚;
4 ---阻止INSERT缓冲区的合并操作。不做合并操作,为防止出现mysqld服务崩溃。不计算表的统计信息
5 ---mysqld服务启动的时候不检查回滚日志:InnoDB引擎对待每个不确定的事务就像提交的事务一样;
6 ---不做事务日志前滚恢复操作;
推荐的参数组合配置:
innodb_fast_shutdown = 1 #若是机房条件较好可设置为0(双路电源、UPS、RAID卡电池和供电系统稳定性)
innodb_force_recovery =0 #至于出问题的时候,设置为何值,要视出错的原因和程度,对数据后续做的操作




innodb_additional_mem_pool_size
含义:开辟一片内存用于缓存InnoDB引擎的数据字典信息和内部数据结构(比如:自适应HASH索引结构);
默认值:build-in版本默认值为:1M;Plugin-innodb版本默认值为:8M;
提示:若是mysqld服务上的表对象数量较多,InnoDB引擎数据量很大,且innodb_buffer_pool_size的值设置
较大,则应该适当地调整innodb_additional_mem_pool_size的值。若是出现缓存区的内存不足,则会直接向
操作系统申请内存分配,并且会向MySQL的error log文件写入警告信息;
innodb_buffer_pool_size
含义:开辟一片内存用于缓存InnoDB引擎表的数据和索引;
默认值:历史默认值为:8M,现在版本默认值为:128M;
参数最大值:受限于CPU的架构,支持32位还是支持64位,另外还受限于操作系统为32位还是64位;
提示信息:
innodb_buffer_pool_size的值设置合适,会节约访问表对象中数据的物理IO。官方手册上建议专用的数据库服
务器,可考虑设置为物理内存总量的80%,但是个人建议要看物理服务器的物理内存总量,以及考虑:
是否只使用InnoDB引擎、mysqld内部管理占用的内存、最大线程连接数和临时表等因素,官方提供的80%值
作为一个参考,举而个例子方便大家作决定,前提为物理服务器为mysqld服务专用,且只用InnoDB引擎,假设数
据量远大于物理内存:
1).内存配置:24G 则innodb_buffer_pool_size=18G
1).内存配置:32G 则innodb_buffer_pool_size=24G
出现下列哪些情况,则可以考虑减小innodb_buffer_pool_size的值:
1).出现物理内存的竞争,可能导致操作系统的分页;
2).InnoDB预分配额外的内存给缓冲区和结构管理,当分配的总内存量超过innodb_buffer_pool_size值的10%;
3).地址空间要求必须为连续的,在windows系统有一个严重问题,DLL需要加载在特定的地址空间;
4).初始化缓冲区的时间消耗,与缓冲区的大小成正比。官方提供的数据Linux X86 64位系统初始化
innodb_buffer_pool_size=10G 大概需要6秒钟





innodb_flush_log_at_trx_commit and sync_binlog
innodb_flush_log_at_trx_commit= N:
N=0 --每隔一秒,把事务日志缓存区的数据写到日志文件中,以及把日志文件的数据刷新到磁盘上;
N=1 –每个事务提交时候,把事务日志从缓存区写到日志文件中,并且刷新日志文件的数据到磁盘上;
N=2 –每事务提交的时候,把事务日志数据从缓存区写到日志文件中;每隔一秒,刷新一次日志文件,但不一定刷新到磁盘上,而是取决于操作系统的调度;
sync_binlog = N:
N>0 --每向二进制日志文件写入N条SQL或N个事务后,则把二进制日志文件的数据刷新到磁盘上;
N=0 --不主动刷新二进制日志文件的数据到磁盘上,而是由操作系统决定;
推荐配置组合:
N=1,1 ---适合数据安全性要求非常高,而且磁盘IO写能力足够支持业务,比如充值消费系统;
N=1,0 ---适合数据安全性要求高,磁盘IO写能力支持业务不富余,允许备库落后或无复制;
N=2,0或2,m(0<m<100) ---适合数据安全性有要求,允许丢失一点事务日志,复制架构的延迟也能接受;
N=0,0 ---磁盘IO写能力有限,无复制或允许复制延迟稍微长点能接受,例如:日志性登记业务




query_cache_type and query_cache_size
query_cache_type=N
N=0 ----禁用查询缓存的功能
N=1 ----启用产讯缓存的功能,缓存所有符合要求的查询结果集,除SELECT SQL_NO_CACHE..,
以及不符合查询缓存设置的结果集外
N=2 ----仅仅缓存SELECT SQL_CACHE …子句的查询结果集,除不符合查询缓存设置的结果集外
query_cache_size
查询缓存设置多大才是合理?至少需要从四个维度考虑:
①查询缓存区对DDL和DML语句的性能影响;
②查询缓存区的内部维护成本;
③查询缓存区的命中率及内存使用率等综合考虑
④业务类型

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


ITeye推荐




基于Storm的Nginx log实时监控系统

$
0
0

背景

UAE(UC App Engine)是一个UC内部的PaaS平台,总体架构有点类似CloudFoundry,包括:

  1. 快速部署:支持Node.js、Play!、PHP等框架
  2. 信息透明:运维过程、系统状态、业务状况
  3. 灰度试错:IP灰度、地域灰度
  4. 基础服务:key-value存储、MySQL高可用、图片平台等

这里它不是主角,不作详细介绍。

有数百个Web应用运行在UAE上,所有的请求都会经过UAE的路由,每天的Nginx access log大小是TB级,如何实时监控每个业务的访问趋势、广告数据、页面耗时、访问质量、自定义报表和异常报警?

Hadoop可以满足统计需求,但秒级的实时性不能满足;用Spark Streaming又有些大材小用,同时我们也没有Spark的工程经验;自写分布式程序调度比较麻烦并且要考虑扩展、消息流动;

最后我们的技术选型定为Storm:相对轻量、灵活、消息传递方便、扩展灵活。

另外,而由于UC的各地集群比较多,跨集群日志传输也会是其中一个比较大的问题。

技术准备

基数计数(Cardinality Counting)

在大数据分布式计算的时候,PV(Page View)可以很方便相加合并,但UV(Unique Visitor)不能。

分布式计算的情况下,几百个业务、数十万URL同时统计UV,如果还要分时段统计(每分钟/每5分钟合并/每小时合并/每天合并),内存的消耗是不可接受的。

这个时候,概率的力量就体现了出来。我们在 Probabilistic Data Structures for Web Analytics and Data Mining可以看到,精确的哈希表统计UV和基数计数的内存比较,并不是一个数量级的。基数计数可以让你实现UV的合并,内存消耗极小,并且误差完全在可接受范围内。

可以先了解 LogLog Counting,理解均匀哈希方法的前提下,粗糙估计的来由即可,后面的公式推导可以跳过。

具体算法是 Adaptive Counting,使用的计算库是 stream-2.7.0.jar

实时日志传输

实时计算必须依赖于秒级的实时日志传输,附加的好处是可以避免阶段性传输引起的网络拥堵。

实时日志传输是UAE已有的轻量级的日志传输工具,成熟稳定,直接拿来用了,包括客户端(mca)和服务器端(mcs)。

客户端监听各个集群的日志文件的变化,传输到指定的Storm集群的各台机器上,存储为普通日志文件。

我们调整了传输策略,使得每台Storm机器上的日志文件大小大致相同,所以Spout只读取本机数据即可。

数据源队列

我们并没有用Storm常用的队列,如Kafka、MetaQ等,主要是太重了…

fqueue是一个轻量的memcached协议队列,把普通的日志文件转为memcached的服务,这样Storm的Spout就可以直接以memcached协议逐条读取。

这个数据源比较简单,它不支持重新发射(replay),一条记录被取出之后就不复存在,如果某个tuple处理失败或超时,则数据丢失。

它比较轻量,基于本地文件读取,做了一层薄的缓存,并不是一个纯内存的队列,它的性能瓶颈在于磁盘IO,每秒吞吐量跟磁盘读取速度是一致的。但对于我们这个系统已经足够,后续有计划改成纯内存队列。

架构

通过上面的技术储备,我们可以在用户访问几秒后就能获取到用户的日志。

discovery_arch

整体架构也比较简单,之所以有两种计算bolt,是基于计算的均匀分布考虑。业务的量相差极大,如果仅按业务ID去进行fieldsGrouping,计算资源也会不均衡。

  1. spout将每条原始日志标准化,按照URL分组(fieldsGrouping,为保持每台服务器计算量的均匀),派发到对应的stat_bolt上;
  2. stat_bolt是主要的计算Bolt,将每个业务的URL梳理并计算,如PV、UV、总响应时间、后端响应时间、HTTP状态码统计、URL排序、流量统计等;
  3. merge_bolt将每个业务的数据合并,如PV数,UV数等。当然,这里的UV合并就用到了前面提到的基数计数;
  4. 自写了一个简单的Coordinator协调类,streamId标记为”coordinator”,作用:时间协调(切分batch)、检查任务完成度、超时处理。原理跟Storm自带的Transactional Topolgoy类似。
  5. 实现一个Scheduler通过API获取参数,动态调整Spout、Bolt在各服务器的分布,以便灵活分配服务器资源。
  6. 支持平滑升级Topology:当一个Topology升级的时候,新Topology和旧Topology讲同时运行,协调切换时间,当新的Topology接管了fqueue之后,过河拆桥,杀死旧的Topology。

注意点:

  • Storm机器尽量部署在同一个机柜内,不影响集群内的带宽;
  • 我们的Nginx日志是按小时切分的,如果切分的时间不准确,在00分的时候,就可以看到明显的数据波动,所以,尽量使用Nginx module去切日志,用crontab发信号切会有延迟。切日志这种10秒级的延迟,在大尺度的统计上没有问题,秒级的统计时波动却很明显;
  • 堆太小会导致woker被强制杀死,所以要配置好-Xmx参数;

自定义项

  • 静态资源:静态资源过滤选项,通过Content-Type或后缀筛选特定的静态资源。
  • 资源合并:URL合并,比如RESTful的资源,合并后方便展示;
  • 维度与指标:通过ANTLR v3做语法、词法分析,完成自定义维度和指标,并且后续的报警也支持自定义表达式。

其他

我们还用其他方式实现了:

  • 业务的进程级(CPU/MEM/端口)监控
  • 业务依赖的服务,如MySQL/memcached等的监控
  • 服务器的磁盘/内存/IO/内核参数/语言环境/环境变量/编译环境等监控

[原]关于Python编程的一些问答

$
0
0

关于Python编程的一些问答

导语

大约1个月前,oschina.net和华章图书一起合作做了一个活动: OSC第51期高手问答——聊聊python那些事,来推广我参与撰写的书《编写高质量代码:改善Python程序的91个建议》( 豆瓣链接)。在回答问题的过程中,我看到有若干问题是好几个人都问了的,就萌发了在事后把这些问答整理整理的想法,以下内容就是来自那一次的问答。为简化整理,已经去掉了提问人的昵称,并做了简单的分类。

纠结的Py2与Py3之选

Q:Python 3 会导致Python的什么前景?最终由3统一,还是一直分裂?各自用自己的版本?

A:py3自发布以来,进步很大,解决了很多py2无法解决的问题,所以我是坚信大家最终会转到py3。现在py3已经有许多非常吸引人的特性,比如yield from,比如asyncio,比如更漂亮的库结构,等等。但我承认py3还没有一个巨大的吸引让大家转过去,yield from 算半个,另外半个我觉得是jit,想像一下py3自带jit,运行速度是py2的3到10倍,大家肯定一窝蜂转过去了。我觉得py3是未来,但也赞同两个割裂的版本影响推广。


Q:新手入门应该学2还是3?2会被Python团队放弃吗?

A:学py2吧,如果到时要转py3也是很容易的事。但如果直接学py3,到时候项目要用py2,就会觉得由奢入俭,很痛苦。


Q:请问您觉得Python3.x需要多久才能成为主流?

A:还有比较长的时间,但如果py3.5有独占的、可靠的、官方的jit方案的话,应该会加速很多很多!


怎样学习Python

Q:Python适合作为一个编程入门语言吗。

A:考虑到就业等,我觉得C语言还是更适合作为入门。


Q:python学习的进阶?基本知识掌握后,该怎么学习?

A:如果已经在工作了,那就直接尝试用python去解决工作需求就好了;如果是学生,那就去复制已存在的网站,把它的功能都弄来,比如oschina。


Q:高质量的代码是怎么写的,怎么提升自己的代码的质量?

A:个人看法:1、熟悉语言的细节;2、熟悉语言和库的最佳实践;3、多看一些提升代码质量的指导书籍;4、同行评审;5、多学几门语言,博采众长。


Q:对一个java开发者来说学习使用python有什么好的建议吗?

A:像当年学习java一样学习它。


Q:初学者,有什么好的网站推荐学习?

A:还是读书、看手册吧,网站的知识太零散,不成体系,容易学成野路子程序员。


Q:学习和使用了一段python后怎么做才能更好的提高自己使用python的能力呢?

A:我的回答是复刻一些产品,比如自己尝试做个豆瓣、oschina之类。


Q:《编写高质量代码:改善Python程序的91个建议》这本书适合其它非Python程序员看吗?

A:不适合。它的定位是对python有所了解的人。给初中级python程序员提升到中高级,这样的定位。


Q:请推荐几个比较优秀的Python开源项目,用来学习的。

A:优秀的python开源项目啊,我想一下,额,看一下trac和reviewboard?


Q:你觉得你学Python以来觉得关于Python最好的书籍有哪些呢?语言基础、语言设计、框架方面,等等都行。谢谢了。

A:很好的问题,我觉得可以回答,因为我自己觉得自己的书也不是“最好的”那个层次。推荐《expert python programming(中译Python高级编程,翻译差强人意)》、《Python源码剖析》。


Q:你好,我有个问题想请教你,如何成为真正的pythoner。我以前是做C++的,现在工作会接触一些python web方面的任务。我最开始接触python的时候学了些基本的语法就开始尝试写与算法相关的程序了,所以写python程序的时候代码还是有C++的影子,直到现在工作中维护之前别人的python web程序的时候,发现自己的python程序太不优雅了,好多时候有的功能可以用更美更快更高效的方式实现,但我可能会像C++里面一样想要从底层一点一草一木的搭建、控制我的程序,后来发现可以几行甚至更短的代码就可以实现那些功能,而且执行效率也更好一点,于是发现写python程序不能用以前C++代码时的思想,或许我可以尝试更pythoner一点?

A:很有意思的一个问题,个人建议如下:1、通读一遍手册,特别是lib ref和lang ref,所谓熟能生巧,对语言本身的熟悉才能写得更pythonic;2、多看一下经典的python项目的文档,比如flask,比如pip,看看他们提供了什么机制,甚至探究到这样的机制是怎么提供的;3、不要担心,多写一些python代码就好了。


应用Python的困惑

Q:Python 适合开发比较复杂的web项目吗?

A:在我看来,python适合开发小中大巨多种复杂程度的项目,因为能不能把项目做成,最关键的因素还是人。python对web支持不错,有许多第三方库,也有django/flask等许多人叫好的框架。


Q:入门Python用哪个操作系统环境好?我就只在Windows上学过一点基础,但不知一般真实团队开发环境是怎样,可以可以介绍下?谢谢!

A:我们一直用linux作为生产环境,mac os x 是我的开发环境,我用过许多年的windows,我不觉得使用windows会影响你的学习。


Q:目前python似乎大多数都是在WEB方向的应用,对于做C语言和C++的开发python有什么可以帮助的地方

A:主要是利用动态语言的灵活性、解释型语言的方便性,来解决C/C++在应变多变的业务需求、快速部署等方面的成本过高或力不从心的问题。


经验之谈

Q:学生,只往PyQt方向发展可行吗?

A:从长远来说,一里通百里融,只要有个突破口,后面有成就也是很可能的。从短期来说,感觉这方面就业面比较窄。


Q:感觉python什么都可以做,但是很难做到很好。如果没有c/c++/go扩展, python能做出大吞吐量,高并发高稳定性的系统吗

A:说python什么都可以做,还是高估了,但说python很难做到很好,就得看“很好”这个词怎么定义了,估计各人的标准还不一样。恕我见识少,好像用go来扩展python还没有成熟方案?目前我经历的网游、网站方面来说,我觉得还可以做出大吞吐量的高并发系统的,只是可能硬件成本会稍高些,至于稳定性,决定性的因素是开发人员的质量,跟语言关系不大,甚至c/c++更容易开发出不稳定的系统。


Q:python 的类库,函数库庞大,如何能快速找到自己需要的类库?

A:这是一个问题,很多语言都有同样的问题。要不你先去看一下 awesome-python 这个项目?


Q:python程序员收入咋样

A:好像年收入从几万到几十万的都见过,但上百万的我还没有见过。总得来说,我觉得跟其它语言的差不多,但高薪的比例可能是比较靠前的。


Q:我原是一名ruby程序员,后来看到python有非常多的模块,如ipython、ipython notebook等非常酷的python应用,其实在灵活性上python远不如ruby(method_missing等),设计哲学也不一样,想问一下为什么python比ruby的应用多很多?特别是科学计算(Numpy)和绘图(matplot)?

A:于python会在科学界这么流行的原因,据说是因为那些科学家都不是计算机专业的,觉得python这货容易学容易用,所以就用这个,反正只是一次性地写写脚本跑一下试验数据。


Q:我想请问,python用来写游戏好么,大家不都说python相对运行起来比c++/c慢,而现在大部分游戏引擎也都是c/c++,就看那个Cocos2d,最先貌似是python版,之后还是用c/c++重写,虽说现在Python版也有更新;另外,现在移动端的各种软件游戏开发也比较热门,python在这方面好像有点跟不上的感觉。

A:是,在手游时代,python已经不合适编写客户端了。可以尝试在服务器端使用它,还是很好的。


Q:我有这么几个问题想请教一下:1. 多框架、多模块的实现语言代表着多学习成本吗2. 胶水语言的存在,现在主要用来做什么,其他层面上是如何应用的3. 类 Unix 系统管理,如何学习他们4. Web 方面与 ruby 之类的有哪些区别,或者说,优缺点5. 写过文字性的爬虫,感觉字符集和平台差异稍有异样,请问您是如何避免的

A:1. 我不太明白多框架、多模块是什么意思,我可以理解为python有很多框架吗?如果是的话,我觉得并不代表更多的学习成本,你看一下quick-start,看一下examples,看一下doc里关于扩展和分拆的机制,就知道这个框架、模块是否适合你的技术观,适合的就行,不适合的就不学,不学不会有成本;2. 胶水语言的这个问题,我觉得《unix编程艺术》这本书里谈得比我讲要好得多,推荐看; 3. 关于sa这一块,我了解不多,建议查阅专著;4. ruby的好处就是有ror这样的大一统解决方案,python是选择多,麻烦也多;4. 文本处理,在编码上的问题很多、很难,建议使用 chardet 等方案,但都是有力不能及的地方的,建议接受部分问题是无法解决的现实。


Q:以下的几个问题想请教一下的:(1) 如何做到高效的python coder, 我也是近这2年才开始用python的,但觉得开化效率还有很多改善的地方,与相对公司内部的java组来说。(2) python 的其中一点我比较喜欢的是比较明了,什么东西都比较原生态,相当于.net来说过于包装,这就是它的长处,如果现成的lib也可以找到,请问一下平时一般常用的东西,是自己做成lib好,还是直接用别人写好的lib好?谢谢(3) python是否比较适合写web呢或是比较好的选择?相对于国内这个环境来说,python这一方面真的比较少些,当然国外有google做带头大哥,它期下的很多projects都很出彩的,我现在做一个web 方面的project,选择bottle,它和flask比较类似,速度方面会较好一点,发现项目进行中遇到不少关于技术方面的问题,可查找到的资料比较少,解决问题相当困难。

A:1. 怎么做高效的python coder,我觉得跟其它语言没有二致,不管怎么样,多读官方文档肯定大有增益,这也是我的经验之谈。2. 我一般直接用别人写好的lib,如果有而且用起来爽的话;3. 建议选择flask/django等社区比较大、比较活跃的框架。


编码一线

Q:个人感觉python没有成熟的IDE,写程序都是文档不停不停地翻,不想写C++或用eclipse,都是自动提示+文档,我想知道是我实在是才疏学浅还是python开发的通病呢?

A:嗯,其实没有特别厉害的IDE,pyCharm是比较好的,而且有免费的社区版,习惯了用E记的,可以试一下pydev。


Q:想问一下,python每import一个模块都会在内存中实例化还是共享一个实例。

A:默认是共享一个。


Q:您是用什么工具打包python工程的?我使用pyinstaller打包包含gtk的程序后,执行打包后的文件会报_glib module 不存在。不知道还有什么更好的工具没。最好是跨平台的。

A:我们一般不打安装包,我们一般就是用setuptools。


Q:python“函数”的返回值类型不在语句的语法声明中,使用python开发项目,由于返回值类型不那么明确,怎么确保在软件迭代中不会弄错?

A:一方面是大家遵守一些最佳实践,比如保证返回值都是同一类型的;二是充分进行单元测试;三是使用较新的python版本,已经支持参数和返回值的类型声明。


Q:对于python 的协程 有什么好的库比较好用

A:必须是gevent。


Q:请问Python有类似Ruby社区RVM、Bundler、Rake的成熟工具链么?

A:有的,pypi.python.org,你可以上去看一下。我书里也有提到这些工具链的用法。

作者:lanphaday 发表于2014-9-1 20:31:34 原文链接
阅读:248 评论:0 查看评论

用WebCollector爬取新浪微博数据

$
0
0

用WebCollector可以轻松爬取新浪微博的数据.

首先需要一个能查看cookie的浏览器插件,推荐使用 firefox浏览器+firebug(插件).

具体步骤:

1.用浏览器打开 http://weibo.cn/pub/   这是新浪微博面对手机用户的一个入口.建议不要使用自己的账号来做爬虫.之所以选择weibo.cn来爬去,是因为这个手机版的限制较少,但是weibo.cn的账号密码都是以明文传输,所以为了防止盗号,建议新申请账号进行爬取.


2.登陆进去后,进入个人微博界面(不是http://weibo.cn/pub/),使用firebug查看网页的cookie,找到cookie中的gsid_CTandWM的属性

记录gsid_CTandWM的值,以后爬虫登陆新浪,全靠这个值.


3.代码:

代码是基于WebCollector的: WebCollector官网

假设我们要爬取周鸿祎的微博信息.周鸿祎的微博主页:http://weibo.cn/u/1708942053(不登陆只能看第一页)

我们爬取前10页.

public static void main(String[] args) throws IOException{
        CollectionGenerator generator=new CollectionGenerator();
        for(int i=1;i<=10;i++){
            generator.addUrl("http://weibo.cn/u/1708942053?page="+i);
        }
        Fetcher fetcher=new Fetcher();
        fetcher.setConconfig(new ConnectionConfig() {
            @Override
            public void config(HttpURLConnection hurlc) {
                hurlc.addRequestProperty("User-Agent", "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:26.0) Gecko/20100101 Firefox/26.0");
                hurlc.addRequestProperty("Cookie", "gsid_CTandWM=上一步中获取的gsid_CTandWM的值;");
            }
        });
        fetcher.setThreads(2);
        fetcher.setHandler(new Handler(){

            @Override
            public void handleMessage(Message msg) {
                Page page=(Page)msg.obj;
                page=ParseUtils.parseDocument(page);
                Elements divs=page.doc.select("div.c");
                for(Element div:divs){                 
                    System.out.println(div.text());
                }
            }
        });
        fetcher.fetchAll(generator);
}


结果(部分):

 2014-09-01 17:57:04 INFO default  - fetch null http://weibo.cn/u/1708942053?page=1 转发了 央视财经 的微博:#互联网时代#【周鸿祎创业秘笈:做互联网买卖 必须尊崇“用户至上”精神】360公司CEO周鸿祎:互联网讲究的不是把东西卖给谁,而是我如何提供有价值的服务,和我的用户永远保持连接,我的用户不是一锤子买卖,是长期的关系。在互联网上网聚人的力量会产生巨大的化学反应。直播地址http://t.cn/RPkRL1I [组图共4张]  原图 赞[122] 原文转发[732] 原文评论[341] 转发理由:很高兴又见到小丫同学风采依旧,她的边看边聊节目很有意思,试图把网络和电视节目结合,就是边看电视边在网上弹幕。算是探索传统媒体融合新媒体。我送她一本我的新书,学习互联网思维。央视是不是应该给每个员工发一本呢  赞[249] 转发[176] 评论[305] 收藏 08月29日 00:13 来自一加手机 不将就
转发了 ChinaVenture投中集团 的微博:【@周鸿祎 :很多厂商只学到小米皮毛】当时我给这些手机厂商讲了很多道理,现在来看其实就是互联网思维。但很可惜没人理解,觉得危言耸听。所有人都看不起小米,都觉得老周在开玩笑。但今天几乎所有手机商都建立了互联网手机品牌,模仿小米玩饥饿营销、粉丝文化。但都是皮毛...http://t.cn/Rhwpl5c  原图 赞[23] 原文转发[170] 原文评论[46] 转发理由:这本书还要卖啊 版税都捐给抗战老兵,所以别把书中内容剪刀浆糊弄出来,强调一下这本书不是360或我的传记,是用互联网很多公司案例讲述互联网思维//现在微博小编都这么没节操吗?我夸奖腾讯百度小米的这些成功案例都出自我的新书《我的互联网方法论》,但你小编把出处写出来就这么难吗?  赞[174] 转发[75] 评论[164] 收藏 08月31日 21:39 来自一加手机 不将就
突然一位朋友私信我,满嘴喷粪,我问他出什么事了 也不回答,谁帮我查查他怎么回事 [组图共2张]  原图 赞[1294] 转发[671] 评论[2475] 收藏 08月28日 23:30 来自一加手机 不将就
转发了 ChinaVenture投中集团 的微博:【@周鸿祎 :很多厂商只学到小米皮毛】当时我给这些手机厂商讲了很多道理,现在来看其实就是互联网思维。但很可惜没人理解,觉得危言耸听。所有人都看不起小米,都觉得老周在开玩笑。但今天几乎所有手机商都建立了互联网手机品牌,模仿小米玩饥饿营销、粉丝文化。但都是皮毛...http://t.cn/Rhwpl5c  原图 赞[23] 原文转发[170] 原文评论[46] 转发理由:现在微博小编都这么没节操吗?我夸奖腾讯百度小米的这些成功案例都出自我的新书《我的互联网方法论》,但你小编把出处写出来就这么难吗?  赞[113] 转发[132] 评论[142] 收藏 08月31日 21:21 来自nubia Z5S mini

注意:爬虫频率不宜过高,建议不要使用过多线程数.


如果有疑问,可加WebCollector官方讨论群:

QQ群:250108697


作者:AJAXHu 发表于2014-9-1 17:58:57 原文链接
阅读:161 评论:0 查看评论

开源公司是如何保持盈利的

$
0
0

open source

英文原文: How Open Source Companies Stay Profitable

目前,有不少的开源解决方案是对公司和个人用户完全免费的。但是,这不意味着“开源”一词就等同于“免费”。

开源项目通常是发达的社区内热情的程序员们通过自愿贡献他们的时间来完成的。尽管如此,关于开源却有另外一个惊人的事实:那些开源公司,比如 Red Hat,它通过提供免费产品获得了超过 10 亿美元的收入。所以,我们可以看出,对于那些提供开源解决方案的公司,它们在不需要你掏腰包,甚至得自己搭上一系列开发费用的情况下依然能够获得丰厚的利润。

企业如何通过各种非传统方法让开源产品给它们带来利润的研究我们在稍后提及,在此之前,让我们来看一下 关于开源软件费用的常见的混淆认识

此“Free”非彼“Free”

根据开源倡议, "free software"与 "open source software" (开源软件)是意思相同,可以互换的两个名词。现在我们来看这个词“free”,这个单词在词典里有“免费”的意思,但这里并不是这个含义。它的真正含义是代表自由—— 以开放源代码的方式从传统的专有式解决方案的壁垒中解放了程序员。

来看一下开源技术的一些主要魅力吧:程序员无需投入大量的时间从头开始构建代码,而是主要采用相互合作的方式创建代码。或者把别人的代码作为一个起点,创建一个新的项目或应用,然后再把成功的作品共享出来,回馈给开源社区的其它用户。

在这些类型的环境中,代码会被定期审查和编辑,以确保最佳的迭代。

开源公司如何赚钱

虽然我们有大量的免费开源解决方案的例子。但是,我们生活的这个世界钱是很重要的,如果开源产品无钱可赚是无法令开发者满意的。为了存在下去,公司需要盈利。让我们来看看开源公司赚钱的五个方式:

  1. 投资

    这是一群富人——多数来自科技领域,所做的常自誉为慈善事业或者称之为购买影响力的行为——无论怎么称呼它,它的本质就是以维持某些开源公司生存来换取富人们的利益。

  2. 双重许可

    你知道《愤怒的小鸟》这款应用么?它不但有一个免费的试用版本还有一个收费的版本。这种情况在开源世界里十分常见。在通常情况下, 开源公司会为它们的软件产品准备双重许可——免费版本和企业版本。这样做的目的是通过免费版让用户喜欢上它,然后让他们购买企业版来获取额外的功能。

  3. 技术支持

    技术支持是围绕着产品而存在的,当产品无法正常运转时,用户最迫切需要的就是技术支持了。一些开源公司基于此 制订了产品技术支持模式,它们让用户免费使用它们的软件,但是必须为优化工作的技术支持支付一定的费用。

  4. 竞争

    有的企业为了从竞争对手那里攫取更大的市场份额而选择在开源社区发布软件和平台。最为著名的例子就是 谷歌将 Android 平台发布到开源社区。当时,苹果的 iOS 占据了智能手机市场。而谷歌通过将 Android 作为一个开放源码平台发布出来之后获得了与多个手机制造商合作的机会。

    最后,Android 成功的占据了智能手机市场的 52.5% 的份额,而苹果只有 41.4%。现在,谷歌应用程序商店里的应用程序数量已经与苹果的旗鼓相当了。在这里,我们可以看到,谷歌将 Android 作为开放源代码平台发布实际是大赚了一笔。

  5. 集资

    著名的网站如 Kickstarter, Indiegogo 和 Bountysource,它们通过以捐款来换取项目奖励的方式进行集资。最近一个开放的笔记本电脑硬件项目 CrowdSupply 筹集了超过 700000 美元,打破了它们 250000 美元的目标。这类集资的方式出现在刚创业的项目和网站并不是一件稀奇的事。

结语

正如你所看到的,开源软件不会花费你一分钱的结论并不成立。它有可能在某些条件下免费,但世界万物,钱之使然,在绝大多数情况下, 免费只是假象。以上就是开源公司获取收入的几种方式,它可以有效地证明:开源绝非免费!

本文链接

AngularJS与服务器交互

$
0
0

        对于AJAX应用(使用XMLHttpRequests)来说,向服务器发起请求的传统方式是:获取一个XMLHttpRequest对象的引用、发起请求、读取响应、检查状态码,最后处理服务端的响应。整个过程示例如下:

var xmlhttp = new XMLHttpRequest();

xmlhttp.onreadystatechange = function() {
    if(xmlhttp.readystate == 4 && xmlhttp.status == 200) {
        var response = xmlhttp.responseText;
    }else if(xmlhttp.status == 400) { //或者可以是任何以4开头的状态码
        //优雅地处理错误
    }
};

//建立连接
xmlhttp.open("GET", "http://myserver/api", true);

//发起请求
xmlhttp.send();

        对于简单、常用而且会经常重复的任务来说,这是一种很烦琐的工作。如果你想复用以上过程,你应该进行封装或者使用代码库。

        AngularJS XHR API遵守一种通常被称为Promise的接口。由于XHR是异步调用的方法,所以服务端的响应会在未来某个不确定的时间点上返回(我们希望它立即能返回)。Promise接口规定了处理这种响应的方式,并且允许Promise的使用者以一种可预见的方式来使用它。

        例如,我们要从服务端获取一个用户的信息,假设用来接受请求的后台接口位于/api/user路径上,此接口可以接受一个id属性作为URL参数,那么使用Angular的核心$http服务发起XHR请求的方法示例如下:

$http.get('api/user', {params: {id:'5'}
}).success(function(data, status, headers, config) {
    //加载成功之后做一些事
}).error(function(data, status, headers, config) {
    //处理错误
});

        如果你是jQuery使用者,你应该会发现,AngularJS和jQuery在对异步请求的处理方面非常类似。

        上面例子中使用的$http.get方法是AngularJS的核心服务$http所提供的众多快捷方法之一。类似地,如果你想使用AngularJS向同一个URL发送POST请求,同时带上一些POST数据,你可以像下面这样做:

var postData = {text:'long blob of text'};
//下面这一行会被当成参数附加到URL后面,所以post请求最终会变成/api/user?id=5
var config = {params: {id: '5'}};
$http.post('api/user', postData, config
).success(function(data, status, headers, config) {
    //成功之后做一些事情
}).error(function(data, status, headers, config) {
    //处理错误
});

        对于大多数常用的请求类型,都有类似的快捷方法,这些请求类型包括:GET、HEAD、POST、DELETE、PUT、JSONP。

一.进一步配置请求

        虽然标准的请求方式使用起来比较简单,但是,有时候会存在可配置性不佳的缺点。如果你想要实现下面这些事情就会遇到困难:

        a.给请求加上一些授权头。

        b.修改对缓存的处理方式。

        c.用一些特殊的方式来变换发送出去的请求,或者变换接收到的响应。

        在这些情况下,你可以给请求传递一个可选的配置对象,从而对请求进行深度配置。在前面的例子中,我们使用config对象指定了一个可选的URL参数。但是那里的GET和POST方法是一些快捷方式。这种深度简化之后的方法调用示例如下:

$http(config)

        下面是一个基本的伪代码模板,用来调用前面的这个方法:

$http({
   method: string,
   url: string,
   params: object,
   data: string or object,
   headers: object,
   transformRequest: function transform(data, headersGetter) or an array of functions,
   transformResponse: function transform(data, headersGetter) or an array of functions,
   cache: boolean or Cache object,
   timeout: number,
   withCredentials: boolean
});

        GET、POST及其他快捷方法都会自动设置method参数,所以不需要手动设置。config对象会作为最后一个参数传递给$http.get和$http.post,所以,在所有的快捷方法内部都可以使用这个参数。你可以传递config对象来修改发送的请求,config对象可以设置以下键值。

        method:一个字符串,表示HTTP请求的类型,例如GET或者POST。

        url:URL字符串,表示请求的绝对或者相对资源路径。

        params:一个键和值都是字符串的对象(确切来说是一个map),表示需要转换成URL参数的键和值。例如:

[{key1: 'value1', key2: 'value2'}]

        将会被转换成

?key1=value&key2=value2

        并会被附加到URL后面。如果我们使用js对象(而不是字符串或者数值)作为map中的值,那么这个js对象会被转换成JSON字符串。

        data:一个字符串或者对象,它会被当作请求数据发送。

        timeout:在请求超时之前需要等待的毫秒数。

 

二.设置HTTP头

        AngularJS带有一些默认的请求头,Angular发出的所有请求上都会带有这些默认的请求头信息。默认请求头包括以下两个:

        1.Accept:appliction/json,text/pain,/

        2.X-Requested-With: XMLHttpRequest

        如果想设置特殊的请求头,可以用如下两种方法实现。

        第一种方法,如果你想把请求头设置到每一个发送出去的请求上,那么你可以把需要使用的特殊请求头设置成AngularJS的默认值。这些值可以通过$httpProvider.defaults.headers配置对象来设置,通常会在应用的配置部分来做这件事情。所以,如果你想对所有的GET请求使用“DO NOT TRACK"头,同时对所有请求删除Requested-With头,可以简单地操作如下:

angular.module('MyApp', []).
    config(function($httpProvider) {
        //删除AngularJS默认的X-Request-With头
        delete $httpProvider.default.headers.common['X-Requested-With'];
        //为所有GET请求设置DO NOT TRACK
        $httpProvider.default.headers.get['DNT'] = '1';
});

        如果你只想对某些特定的请求设置请求头,但不把它们作为默认值,那么你可以把头信息作为配置对象的一部分传递给$http服务。同样的,自定义头信息也可以作为第二个参数的一部分传递给GET请求,第二个参数还可以同时接受URL参数。

$http.get('api/user', {
     //设置Authorization(授权)头。在真实的应用中,你需要到一个服务里面去获取auth令牌
     headers: {'Authorization': 'Basic Qzsda231231'},
     params: {id:5}
}).success(function() {//处理成功的情况 });

 

三.缓存响应

        对于HTTP GET请求,AngularJS提供了一个开箱即用的简单缓存机制。默认情况下它对所有请求类型都不可用,为了启用缓存,你需要做一些配置:

$http.get('http://server/myapi', {
    cache: true
}).success(function() {//处理成功的情况});

        这样就可以启用缓存,然后AngularJS将会缓存来自服务器的响应。下一次向同一个URL发送请求的时候,AngularJS将会返回缓存中的响应内容。缓存也是智能的,所以即使你向同一个URL发送多次模拟的请求,缓存也只会向服务器发送一个请求,而且在收到服务端的响应之后,响应的内容会被分发给所有请求。

        但是,这样做有些不太实用,因为用户会先看到缓存的旧结果,然后看到新的结果突然出现。例如,当用户即将点击一条数据时,它可能会突然发生变化。

        注意,从本质上来说,响应(即使是从缓存中读取的)依然是异步的。换句话说,在第一次发出请求的时候,你应该使用处理异步请求的方式来编码。

 

四.转换请求和响应

        对于所有通过$http服务发出的请求和收到的响应来说,AngularJS都会进行一些基本的转换,包括如下内容。

1.转换请求

        如果请求的配置对象属性中包含JS对象,那么就把这个对象序列化成JSON格式。

2.转换响应

        如果检测到了XSRF(Cross Site Request Forgery的缩写,意为跨站请求伪造,这是跨站脚本攻击的一种方式)前缀,则直接丢弃。如果检测到了JSON响应,则使用JSON解析器对它进行反序列化。

        如果你不需要其中的某些转换,或者想自已进行转换,可以在配置项里面传入自已的函数。这些函数会获取HTTP的request/response体以及协议头信息,然后输出序列化、修改之后的版本。可以使用transformLRequest和transformResponse作为key来配置这些转换函数,而这两个函数在模块的config函数中是用$httpProvider服务来配置的。

        我们什么时候需要使用这些东西呢?假设我们有一个服务,它更适合用jQuery的方式来操作。POST数据使用key1=val1&key2=val2(也就是字符串)形式来代替{key1:val1, key2:val2}JSON格式。我们可以在每个请求中来进行这种转换,也可以添加一个独立transformRequest调用,对于当前这个例子来说,我们打算添加一个通用的transformRequest,这样所有发出的请求都会进行这种从JSON到字符串的转换。下面就是实现方式:

var module = angular.module('myApp');

module.config(function($httpProvider) {
    $httpProvider.defaults.transformRequest = function(data) {
          //使用jQuery的param方法把JSON数据转换成字符串形式
          return $.param(data);
     };
});

 

文章来源:《用AngularJS开发下一代Web应用》



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


ITeye推荐



Spring的WebServiceTemplate访问WebService的方法及其本质原理

$
0
0

WebService客户端调用的本质就是将SAOP格式的XML通过通信协议发送到WebService的服务器端,然后接收服务器端返回的XML.

 

本文简单介绍一下如何通过Spring提供的WebServiceTemplate访问 Webservice,WebServiceTemplate与调用webservice的客户端已及webservice服务器端示意图如下(图片来源 于Spring in Action):

 

 

这里以SOAP over HTTP为例,开发步骤如下:

1,在Spring的配置文件中配置WebServiceTemplate,最简单的配置如下:

<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">  <property name="defaultUri" value="http://localhost:8080/prjCXFWS/services/SimpleServicePort"/>  </bean>     

 *这种配置省略了MessageFactory和messageSender的配置,Spring默认会使用SaajSoapMessageFactory和HttpUrlConnectionMessageSender.等同于下面的配置

<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>  <bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">  <constructor-arg ref="messageFactory"/>  <property name="messageSender">  <bean class="org.springframework.ws.transport.http.HttpUrlConnectionMessageSender"/>  </property>  <property name="defaultUri" value="http://localhost:8080/prjCXFWS/services/SimpleServicePort" />  </bean>  

 还可以使用CommonsHttpMessageSender作为messageSender,它提供了设置timeout,用户名,密码等选项的功能.(需要使用commons-httpclient.jar和commons-codec.jar)
MessageFactory还可以使用AxiomSoapMessageFactory和DomPoxMessageFactory.

<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">  <property name="messageSender">  <bean class="org.springframework.ws.transport.http.CommonsHttpMessageSender">  <property name="readTimeout" value="0" />  </bean>  </property>  <property name="defaultUri" value="http://localhost:8080/prjCXFWS/services/SimpleServicePort" />  </bean>  

 2,Java调用代码:传输的是SOAP XML.

    private static final String MESSAGE =  "<queryPeopleByID  xmlns=\"http://test.cxfws.com\">1231ss</queryPeopleByID> ";  
    public static void test() {  
        ApplicationContext ac = new ClassPathXmlApplicationContext("conf/wsAppcontext.xml");  
        WebServiceTemplate simpleService = (WebServiceTemplate) ac.getBean("webServiceTemplate");  
        StreamSource source = new StreamSource(new StringReader(MESSAGE));  
           StreamResult result = new StreamResult(System.out);          
           simpleService.sendSourceAndReceiveToResult(source, result);  
    }  

 *MESSAGE为需要发送到webservice服务器端的XML payload内容,SOAP body之内的XML内容.

Spring调用Webservice的另一种方法是通过Spring提供的JaxWsPortProxyFactoryBean,示意图如下(图片来源于Spring in Action):

Spring的配置如下:

<bean id="simpleService"  
        class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">  <property name="serviceInterface"  
            value="com.cxfclient.test.SimpleService" />  <property name="wsdlDocumentUrl"  
            value="http://localhost:8080/prjCXFWS/services/SimpleServicePort?WSDL" />  <property name="namespaceUri" value="http://test.cxfws.com/" />  <property name="serviceName" value="SimpleServiceService" />  <property name="portName" value="SimpleServicePort" />  </bean>  

 **这种方式需要用工具通过Webservice 的wsdl文件生成客户端需要的一些Java类,如service的interface,参数类等等(如下面代码中的SimpleService,People类).
Java调用代码如下

    ApplicationContext ac = new ClassPathXmlApplicationContext("conf/wsAppcontext.xml");  
    SimpleService simpleService = (SimpleService) ac.getBean("simpleService");  
    People people = simpleService.queryPeopleByID("test");  
    System.out.println(people.getAge() + people.getName() + people.getPid());  

 关于更多客户端如何调用webservice,参照http://blog.csdn.net/kkdelta/article/details/3987591
对于服务器端,其本质也是接收符合SOAP规范的XML消息,解析XML,返回符合SOAP规范的XML,这里用一个servlet模拟webservice,代码如下:

    public class WSSimulator extends HttpServlet {  
        public void doGet(HttpServletRequest request, HttpServletResponse response)  
        throws IOException {  
            System.out.println("doGet");  
            BufferedReader in = new BufferedReader(new InputStreamReader( request.getInputStream()));  
            String str;  
            while ((str = in.readLine()) != null) {  
                System.out.println(str); ##1  
            }  
            in.close();  
            String soapHeader = "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">"   
                +"<SOAP-ENV:Header/><SOAP-ENV:Body>";  
            String soapPayload = "<xxx>yyy</xxx>";  
            String soapTail = "</SOAP-ENV:Body></SOAP-ENV:Envelope>";         
            response.getWriter().write(soapHeader + soapPayload + soapTail);  ##2     
        }  
        public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {  
            System.out.println("doPost");  
            doGet(request, response);  
        }  
    }  

 通过WebServiceTemplate将消息发送到这个servlet监听的url,可以更深理解Webservice的本质.
##1 str就是从客户端传输到服务器端的XML.##2将SOAP消息返回给客户端.
更多服务器端webservice的开发请参照http://blog.csdn.net/kkdelta/article/details/3984312



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


ITeye推荐



基于jasig的sso

$
0
0
<div class="iteye-blog-content-contain" style="font-size: 14px"></div>
整体的结构就是cas+shiro实现单点登录和权限管理。怎么安装就不说了网上一大堆,在这总结一些问题的处理方法
1、未能识别出目标票根
org.jasig.cas.client.validation.TicketValidationException: 
未能够识别目标'ST-2-jEo1qANhs9HgZ7VKC5Hf-cas'票根

原因:是由于客户端应用web.xml配置中的casServerLoginUrl和casServerUrlPrefix两个URL属性的域名与证书中定义的不一致,或者你的地址配置的不对,配置serverUrl就到cas配置serviceUrl就到端口号

2、循环重定向
解决方案为查看service与loginUrl中的是否一致,这是两个概念,service是请求的页面,当用户访问这个页面是会跳转至公共的验证平台,而loginUrl中的service是回调的地址,如果两个地址设定为同一地址的话就会出现循环重定向的问题

3、自定义验证报异常
cas登录端修改cas-server-surport-jdbc包中的class要保证与原cas所用包的环境一致,替换class后运行tomcat会包creating bean exception这是缺少mysql的jar包导入就可以了

4、配置客户端返回更多信息,具体的配置过程网上很多这里只提报错。
误区:<constructor-arg index="1" value="select * from user where username=?"/> 这是正确的配置方法
<constructor-arg index="1" value="select * from user where {0}"/> 这是错误的配置方法

5、去掉cas地址栏的sessionid
top.jsp session=false 例<%@ page session="false" %>  去掉Url中的sessionid

6、shiro的集成
shiro加入主要有什么意义呢?我总结了以下几点:a、大局上的权限控制,shiro提供从角色到权限的系统化校验,而且shiro的加密也是较比传统更安全啊。b、shiro可以过滤url。我们很多情况下需要cas放过某些url并不是/*式的拦截,如何能细颗粒的控制这些url,显然通过cas的filter映射拦截是不能尽如人意的,所以我们引入shiro,可以指定需要过滤的url为anon,需要保护的就指定为authc。还可以基于角色过滤等等。c、shiro提供很成熟的session机制,可以配合cas的票据完美保存cas的会话。d、如果用户非常态登录,不通过正常的login登录那么回跳到应用的时候就会有一些问题,我们集成了shiro之后就可以拿到重定向前的请求放在shirosaverequest里,这样就可以解决回跳重定向的问题了

7、cas的集群
cas集群我这里用到的是tomcat,只需要配置tomcat的session共享就可以了

未尽 待完善

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


ITeye推荐




将android程序中的数据库导出到SD卡

$
0
0
	private void copyDBToSDcrad()
	{
		String DATABASE_NAME = "数据库文件名称";
		String oldPath = "data/data/com.packagename/databases/" + DATABASE_NAME;
		String newPath = Environment.getExternalStorageDirectory() + File.separator + DATABASE_NAME;
		copyFile(oldPath, newPath);
	}

	/**
	 * 复制单个文件
	 * 
	 * @param oldPath
	 *            String 原文件路径
	 * @param newPath
	 *            String 复制后路径
	 * @return boolean
	 */
	public static void copyFile(String oldPath, String newPath)
	{
		try
		{
			int bytesum = 0;
			int byteread = 0;
			File oldfile = new File(oldPath);
			File newfile = new File(newPath);
			if (!newfile.exists())
			{
				newfile.createNewFile();
			}
			if (oldfile.exists())
			{ // 文件存在时
				InputStream inStream = new FileInputStream(oldPath); // 读入原文件
				FileOutputStream fs = new FileOutputStream(newPath);
				byte[] buffer = new byte[1444];
				while ((byteread = inStream.read(buffer)) != -1)
				{
					bytesum += byteread; // 字节数 文件大小
					fs.write(buffer, 0, byteread);
				}
				inStream.close();
			}
		}
		catch (Exception e)
		{
			System.out.println("复制单个文件操作出错");
			e.printStackTrace();

		}

	}

作者:pmtoam 发表于2014-9-2 12:30:02 原文链接
阅读:67 评论:0 查看评论

如何用Java编写一段代码引发内存泄露

$
0
0

文本来自StackOverflow问答网站的一个热门讨论:如何用Java编写一段会发生内存泄露的代码。

Q:刚才我参加了面试,面试官问我如何写出会发生内存泄露的Java代码。这个问题我一点思路都没有,好囧。

A1:通过以下步骤可以很容易产生内存泄露(程序代码不能访问到某些对象,但是它们仍然保存在内存中):

  1. 应用程序创建一个长时间运行的线程(或者使用线程池,会更快地发生内存泄露)。
  2. 线程通过某个类加载器(可以自定义)加载一个类。
  3. 该类分配了大块内存(比如 new byte[1000000]),在某个静态变量存储一个强引用,然后在ThreadLocal中存储它自身的引用。分配额外的内存 new byte[1000000]是可选的(类实例泄露已经足够了),但是这样会使内存泄露更快。
  4. 线程清理自定义的类或者加载该类的类加载器。
  5. 重复以上步骤。

由于没有了对类和类加载器的引用,ThreadLocal中的存储就不能被访问到。ThreadLocal持有该对象的引用,它也就持有了这个类及其类加载器的引用,类加载器持有它所加载的类的所有引用,这样GC无法回收ThreadLocal中存储的内存。在很多JVM的实现中Java类和类加载器直接分配到permgen区域不执行GC,这样导致了更严重的内存泄露。

这种泄露模式的变种之一就是如果你经常重新部署以任何形式使用了ThreadLocal的应用程序、应用容器(比如Tomcat)会很容易发生内存泄露(由于应用容器使用了如前所述的线程,每次重新部署应用时将使用新的类加载器)。

A2:

静态变量引用对象

class MemorableClass {
    static final ArrayList list = new ArrayList(100);
}

调用长字符串的String.intern()

String str=readString(); // read lengthy string any source db,textbox/jsp etc..
// This will place the string in memory pool from which you cant remove
str.intern();

未关闭已打开流(文件,网络等)

try {
    BufferedReader br = new BufferedReader(new FileReader(inputFile));
    ...
    ...
} catch (Exception e) {
    e.printStacktrace();
}

未关闭连接

try {
    Connection conn = ConnectionFactory.getConnection();
    ...
    ...
} catch (Exception e) {
    e.printStacktrace();
}

JVM的GC不可达区域

比如通过native方法分配的内存。

web应用在application范围的对象,应用未重启或者没有显式移除

getServletContext().setAttribute("SOME_MAP", map);

web应用在session范围的对象,未失效或者没有显式移除

session.setAttribute("SOME_MAP", map);

不正确或者不合适的JVM选项

比如IBM JDK的noclassgc阻止了无用类的垃圾回收

A3:如果HashSet未正确实现(或者未实现) hashCode()或者 equals(),会导致集合中持续增加“副本”。如果集合不能地忽略掉它应该忽略的元素,它的大小就只能持续增长,而且不能删除这些元素。

如果你想要生成错误的键值对,可以像下面这样做:

class BadKey {
   // no hashCode or equals();
   public final String key;
   public BadKey(String key) { this.key = key; }
}

Map map = System.getProperties();
map.put(new BadKey("key"), "value"); // Memory leak even if your threads die.

A4:除了被遗忘的监听器,静态引用,hashmap中key错误/被修改或者线程阻塞不能结束生命周期等典型内存泄露场景,下面介绍一些不太明显的Java发生内存泄露的情况,主要是线程相关的。

  • Runtime.addShutdownHook后没有移除,即使使用了removeShutdownHook,由于ThreadGroup类对于未启动线程的bug,它可能不被回收,导致ThreadGroup发生内存泄露。
  • 创建但未启动线程,与上面的情形相同
  • 创建继承了 ContextClassLoaderAccessControlContext的线程, ThreadGroupInheritedThreadLocal的使用,所有这些引用都是潜在的泄露,以及所有被类加载器加载的类和所有静态引用等等。这对 ThreadFactory接口作为重要组成元素整个j.u.c.Executor框架(java.util.concurrent)的影响非常明显,很多开发人员没有注意到它潜在的危险。而且很多库都会按照请求启动线程。
  • ThreadLocal缓存,很多情况下不是好的做法。有很多基于ThreadLocal的简单缓存的实现,但是如果线程在它的期望生命周期外继续运行ContextClassLoader将发生泄露。除非真正必要不要使用ThreadLocal缓存。
  • 当ThreadGroup自身没有线程但是仍然有子线程组时调用 ThreadGroup.destroy()。发生内存泄露将导致该线程组不能从它的父线程组移除,不能枚举子线程组。
  • 使用WeakHashMap,value直接(间接)引用key,这是个很难发现的情形。这也适用于继承 Weak/SoftReference的类可能持有对被保护对象的强引用。
  • 使用http(s)协议的 java.net.URL下载资源。 KeepAliveCache在系统ThreadGroup创建新线程,导致当前线程的上下文类加载器内存泄露。没有存活线程时线程在第一次请求时创建,所以很有可能发生泄露。 (在Java7中已经修正了,创建线程的代码合理地移除了上下文类加载器。)
  • 使用 InflaterInputStream在构造函数(比如 PNGImageDecoder)中传递 new java.util.zip.Inflater(),不调用inflater的 end()。仅仅是new的话非常安全,但如果自己创建该类作为构造函数参数时调用流的 close()不能关闭inflater,可能发生内存泄露。这并不是真正的内存泄露因为它会被finalizer释放。但这消耗了很多native内存,导致linux的oom_killer杀掉进程。所以这给我们的教训是:尽可能早地释放native资源。
  • java.util.zip.Deflater也一样,它的情况更加严重。好的地方可能是很少用到 Deflater。如果自己创建了 Deflater或者 Inflater记住必须调用 end()

可能感兴趣的文章

Android平台渗透测试套件zANTI 2.0版发布

$
0
0

zANTI是Android平台下的渗透测试套件,最 优雅、最美观的渗透测试套件之一。

现已推出2.0版本:

zANTI 2.0 enhancements for community users now include:

  • zPacketEditor – 用于中间人攻击(MITM)测试时可进行人工渗透测试

  • ICMP重定向 – 使用ICMP重定向支持全双工MITM

  • MITM特性 – 可拦截下载、重定向URL图片替换和插入HTML

  • Password复杂性审计 – 可使用大型、巨型和自定义字典进行暴力破解测试

为了推广自家的zIPS,MITM工具现可 完全免费使用

下载地址1

下载地址2

SHA1: a4893c1bedf368a9c42699e2bff0198408a26e7b

Java地位无可动摇的12个原因

$
0
0

如今,面对曾经在程序员中被各种新技术掩盖直至堙灭的技术值得怀念。犹如COBOL这当年被老程序员们尊为神器的语言如今也基本没有价值。而Java作为现代程序员的中坚力量在这点上或许会成为下一个COBOL。

有关JAVA的技术卖出多少本书已经是一个很久远的记忆了。现处中年时期的Java语言的用途已经不再出现在各种杂志的封面上了。JAVA从出生到现在已经19年了,应用开发圈已经开始绕着那些更有吸引力的新技术。Java或许是Web 1.0时代的一个传说。

从招聘信息你就可以知道,跟iOS相关的开发有2500左右的招聘,Java则有17000多个。数据不一定能完美的衡量技术的价值,但是在不断推陈出新的技术推广压力下,Java职位是iOS的7倍之多可以说明问题。

在忘记Java在计算机行业里所扮演的角色和做出的那些卓越贡献前,有12个绝对的理由来告诉你Java不但不会和COBOL一样被堙灭,并且在其后时代中更加壮大。换句话说:Java一直就在并且其地位无法撼动。

Java在市场斗争中不屈不挠

技术界从来没认为Java会成功,尽管它的对手太多但依然繁荣发展起来。那些诧异Java仍然存在的人们并没有真正去理解为什么Java会成功。微软是 Java第一个面对的强大对手,因为那时MS-DOS提供了通用性,而微软看到Java是此通用性最具可能性的替代者。

此外,苹果Steve Jobs从来没接收过Java,即使是在Mac被除了Adobe之外所有人忽视的年代。Java的兼容性可以带来很多有用的代码,但是Apple一直未把Java视作第一选择。

Java内部的很多斗争也给它带来了巨大痛苦。IBM喜欢Java,但是一直在和Sun斗争。IBM将其开发的优秀的IDE工具称为“Eclipse”的决定,一直没被Sun的人员欣然接受。Sun也从来没像IBM那样深刻理解商业领域。

尽管这些原因,尽管Java创造者也在Java发展中有许多失策之处,Java依然快速壮大,在服务器应用领域如鱼得水,在桌面应用领域满足基本业务需求。

Java虚拟机优化线程的魔力

Java虚拟机的强项之一是多线程控制。JVM针对大型多核机上数百线程的稳定性做了极佳的优化。其他语言会为了能跑在JVM上面搞出交叉编译器和模拟 器。Java的这个能力同时也吸引了很多高流量的网站。他们可以在台式机上搞开发然后丢到服务器上让JVM发挥出多核的功效。

Ruby因为语法的简洁和源码可读性好成为了Java目前的一个对手。但是当性能成为瓶颈时,Ruby开发人员转到了JRuby,一个用Java模拟出来的Ruby环境并增强了高负载下的线程处理能力。

Java成为编程初学者的语言

作为大学AP计算机课程,意味着在美国很多学生第一次接触到的计算机语言就是Java。由于这个先入为主的原因,当他们学习其他新的语言时,即便转行学其他语言课程,但是他们在思考的时仍会受到Java的影响。

关注:Java地位无可动摇的十二个原因

(图片来源chron.com)
Java作为一个教学语言是有它的原因的。声明数据类型看上去可能比较抽象,但是为了能让初学者理解计算机的原理,声明数据类型通过编译器会告诉他们数 据类型不匹配而无法编译时,可以让他们更好的理解计算机的底层原理。而一些新语言已经摒弃了花括号,维护麻烦使得新人有所厌倦,但是花括号对那些新手是非 常有用的,因为能帮助他们理解嵌套的代码块。

Java具有跨平台兼容性

虽然Java并不是第一个提供跨平台兼容能力的语言,但是Java已经成为最受欢迎的跨平台编程工具,Sun以及Oracle已经为程序可以跨平台使用提供支持。当程序不能在多个平台上使用时,导致问题的原因通常是可以解决的。

Java程序员可以使用他们的桌面开发工具进行编码,并部署到目标设备,可能是一台手机或者一台服务器。如果编译器包含了正确的库并且使用了正确的版本,代码就可以运行。

关注:Java地位无可动摇的12个原因

Java在移动领域上的持续成功

Java也许并没在大型应用程序中有很好体现,但它却在移动领域的细分市场获得快速发展。Android平台从上到下都是基于Java构建起来的,并且它如今的销量轻易的超过了iPhone。JAVA ME作为精简版的语言和VM已经被广泛应用在智能手机上,而智能手机如今已经遍布在全世界。

Java在蓝光应用取得突破

Java曾经为机顶盒而设计的语言,Sun想在占据此市场,但是Java却在另外领域中找到了合适的位置。蓝光标准是围绕Java建立,任何想在蓝光光 碟中添加额外内容的人,必须得到其Javac编译器版本。蓝光光碟不止限于存放视频内容。那些额外特性和交互工具可以使用纯Java代码修改并增强。压缩 后的视频和压缩后的Java字节码的混合。

Java让花括号能优化代码工作

类似 Ruby、Python或CoffeeScript等语言的开发者对于Java要求程序员们敲打花括号键来明确表达代码段的开始和结束。括号、花括号、甚 至方括号对于程序员略显多余。但是改变符号并不能消除复杂性,使用像制表符等空白后你只能用直觉去感受那些无法看到的东西。

如果if语句只引导了一行代码,这样不会有问题,但是当很多层嵌套时,就很难看明白。当用Python编程时,并不意味着代码像理解英文简单。

Java动态类型语法工具Groovy

Java开发者必须要有一个带有动态类型的语法,可以使用Groovy一个带有预处理器的工具,它能够生成出Java字节码来。这种语言也完全集成到了Java中,因此可以在Groovy中混入对Java库的调用。就像是编写Java代码的缩略形式。

这一灵活性让开发工程师得以找到问题的出路。在使用了动态方法调用时,开发者可以用Java来重写重要的核心操作。

Java虚拟机让编程更加的灵活

Java虚拟机是按照运行Javac编译器产生的代码源头来设计和优化,但开发者们意识到Java虚拟机也可以运行其他代码。只要编译器们产出标准的 Java字节码,Java虚拟机根本不关心是使用的那种编程语言。Haskell、Scala和Clojure的开发者们设计编译器就采用Java,而只 是这个由Java虚拟机产生的。

另外,Sun/Oracle 为创建跨平台环境而努力,工程师们消除平台间差异,并考虑兼容性问题,然后所有人可以运行他们想运行的程序。微软在创建C#时为大部分主要语言设计了编译 器,使得C#虚拟机可以运行这些语言编写的所有程序。C#程序员可以用很多不同的语言编写程序,只要通过一个Windows盒子将其运行在一个虚拟机上即 可。

关注:Java地位无可动摇的十二个原因

NoSQL建立在Java之上

数据库是保存信息并快速有效应对查询请求。NoSQL的出现让程序员们可以自己编写数据库,并根据需求修剪其代码。那些最重要NoSQL工具中很多都是 用Java编写。Cassandra、Lucene、ElasticSearch、HBase和Neo4J只是一些经常提到的NoSQL选择。

据了解,工具通常是开源的。开发者将其独立运行,或将它们集成在自己的模块中,使得Java在数据库层中成为通用语言,保证了Java开发者们担心由于字符编码和行结束符带来的故障。这意味着Java开发者们可以享受由NoSQL革命带来的丰硕果实。

Minecraft游戏中00后的情结

非主流们对Java嗤之以鼻,但是Java程序员们却领先一步。在Ruby时尚团正聚集起自己的一群粉丝时,Minecraft让之后的一代人爱上了Java。它用Java编写而成,要扩展该游戏就需学习Java来设计其插件,这保证下一代程序员首选是Java。

开源成就Java代码广泛的应用

Sun一直是开源领域中的领导者之一,Java程序员们发布众多开源许可的库和项目。Apache项目一直都在使用一个没要求太多回报的许可证来提供优 秀的Java代码。07年完成在GPL许可下公开大部分代码的工作,这种开放的立场一直延续并保证Java平台很大程度是开放和免费的。

由此,Java有自己的问题,花括号增加混乱等缺点。但目前还没有一个广度和深度上可与之竞争的语言。最接近的也许是JavaScript,依靠有闪电般速度的Node.js在服务器领域受到广泛关注。而语言是开源且灵活多变,意味着Java程序继续存在甚至更加兴旺。

全文检索引擎Solr系列——整合中文分词组件IKAnalyzer

$
0
0

IK Analyzer是一款结合了词典和文法分析算法的中文分词组件,基于字符串匹配,支持用户词典扩展定义,支持细粒度和智能切分,比如:

张三说的确实在理

智能分词的结果是:

张三 |  说的 |  确实 |  在理 

最细粒度分词结果:

张三 |  三 |  说的 |  的确 |  的 |  确实 |  实在 |  在理

整合IK Analyzer比mmseg4j要简单很多, 下载解压缩IKAnalyzer2012FF_u1.jar放到目录:E:\solr-4.8.0\example\solr-webapp\webapp\WEB-INF\lib,修改配置文件schema.xml,添加代码:

<field name="content" type="text_ik" indexed="true" stored="true"/> <fieldType name="text_ik" class="solr.TextField"><analyzer type="index" isMaxWordLength="false" class="org.wltea.analyzer.lucene.IKAnalyzer"/><analyzer type="query" isMaxWordLength="true" class="org.wltea.analyzer.lucene.IKAnalyzer"/></fieldType>
查询采用IK自己的最大分词法,索引则采用它的细粒度分词法

此时就算配置完成了,重启服务:java -jar start.jar,来看看IKAnalyzer的分词效果怎么样,打开Solr管理界面,点击左侧的Analysis页面

默认分词器进行最细粒度切分。IKAnalyzer支持通过配置IKAnalyzer.cfg.xml 文件来扩充您的与有词典以及停止词典(过滤词典),只需把IKAnalyzer.cfg.xml文件放入class目录下面,指定自己的词典mydic.dic

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">   <properties>   <comment>IK Analyzer 扩展配置</comment> <!--用户可以在这里配置自己的扩展字典  -->  <entry key="ext_dict">/mydict.dic; 
    /com/mycompany/dic/mydict2.dic;</entry>  <!--用户可以在这里配置自己的扩展停止词字典--> <entry key="ext_stopwords">/ext_stopword.dic</entry>    </properties> 

事实上前面的FieldType配置其实存在问题,根据目前最新的IK版本 IK Analyzer 2012FF_hf1.zip索引时使用最细粒度分词,查询时最大分词(智能分词)实际上是不生效的。

据作者 linliangyi说,在2012FF_hf1这个版本中已经修复,经测试还是没用,详情请看 此贴

解决办法:重新实现IKAnalyzerSolrFactory

 package org.wltea.analyzer.lucene;
    import java.io.Reader;
    import java.util.Map;
    import org.apache.lucene.analysis.Tokenizer;
    import org.apache.lucene.analysis.util.TokenizerFactory;
    //lucene:4.8之前的版本
    //import org.apache.lucene.util.AttributeSource.AttributeFactory;
    //lucene:4.9
    import org.apache.lucene.util.AttributeFactory;
    
    public class IKAnalyzerSolrFactory extends TokenizerFactory{
        
        private boolean useSmart;
        
        public boolean useSmart() {
            return useSmart;
        }
        
        public void setUseSmart(boolean useSmart) {
            this.useSmart = useSmart;
        }
        
         public IKAnalyzerSolrFactory(Map<String,String> args) {
             super(args);
             assureMatchVersion();
             this.setUseSmart(args.get("useSmart").toString().equals("true"));
           }
        @Override
        public Tokenizer create(AttributeFactory factory, Reader input) {
            Tokenizer _IKTokenizer = new IKTokenizer(input , this.useSmart);
            return _IKTokenizer;
        }
    }

重新编译后更新jar文件,更新schema.xml文件:

<fieldType name="text_ik" class="solr.TextField" ><analyzer type="index"><tokenizer class="org.wltea.analyzer.lucene.IKAnalyzerSolrFactory" useSmart="false"/></analyzer> <analyzer type="query"><tokenizer class="org.wltea.analyzer.lucene.IKAnalyzerSolrFactory" useSmart="true"/></analyzer> </fieldType>

相关文章

Viewing all 15843 articles
Browse latest View live


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