2016年1月29日星期五

Mac中运行shell脚本command not found问题

写了一个a.sh文件:
#!/bin/bash
echo "hello"

通过 bash a.sh 或者 sh a.sh 执行都没有问题。

但 sudo ./a.sh 执行的时候报下面的错:
sudo: ./a.sh: command not found

解决方法,给该文件添加执行权限:
sudo chmod a+x a.sh
完成。

使用grep、sed、awk、sort统计日志文件中的字段

遇到这样一个需求,统计hdfs中log文件中的某个字段,log文件每一行格式如下:
{"msgid":"478721ef-ff6e-42b1-a2fb-97bba74c7bac","request_json":"{\"address\":\"中国,山东,临沂,罗庄,,,35.01737326529004,118.29531628357033\",\"appkey\":\"com.google\",\"channel\":\"aw_sdk\",\"device_id\":\"b61f0da076b9a88547c3b790014bd21d\",\"msg_id\":\"478721ef-ff6e-42b1-a2fb-97bba74c7bac\",\"output\":\"\",\"query\":\"on_peer_connected\",\"query_type\":\"event\",\"remote_ip\":\"\",\"task\":\"\",\"user_id\":\"b61f0da076b9a88547c3b790014bd21d\",\"version\":\"\",\"watch_build\":\"LHA72H\",\"watch_device_id\":\"7c0f71560710fe730e9b8d08ab7b7b00\"}","status":"success","msg_type":"event","lng":"118.295","wechat_user_id":"3790728","deviceid":"b61f0da076b9a88547c3b790014bd21d","qa_classification":"","qa_result":"{}","id":"56741496","content":"on_peer_connected","speech_id":"NULL","updated_at":"2015-10-08 15:27:43","wechat_app_id":"62","address":"中国,山东,临沂,罗庄,,,35.01737326529004,118.29531628357033","created_at":"2015-10-08 15:27:43","historical":"NULL","lat":"35.0174"}

需求是统计所有不同的watch_build的个数,一个可行的方法是直接使用grep先过滤出含有watch_build字段的log,然后sed截取watch_build,最后awk计算求和:
hdfs dfs -cat /data/log/offline/process/weiyuyi/2016/01/26/* | grep watch_build | sed 's/\(.*\)\(watch_build\)\\":\\"\([^\]*\)\(.*\)/\2:\3/g' | awk 'BEGIN{FS=":"} {a[$2]++;} END {for (i in a) print i ", " a[i];}'

或者使用sort,可以不用awk:
hdfs dfs -cat /data/log/offline/process/weiyuyi/2016/01/26/* | grep watch_build | sed 's/\(.*\)\(watch_build\)\\":\\"\([^\]*\)\(.*\)/\2:\3/g' | sort | uniq -c | sort -n -r

sed简明教程:link
awk简明教程:link

一个sed的简单例子,使用sed提取子字符串:
  testchenxiaoyuage20xxx,提取chenxiaoyu和20,格式为chenxiaoyu:20
  echo "testchenxiaoyuage20xxx" | sed 's/.*\(chenxiaoyu\)age\([0-9]*\).*/\1:\2/g'
  其中:
    .* 表示匹配任意文本;
    被 \( 和 \) 之间括起来的内容被自动按顺序编上了号,后面可以使用 \1 \2 等等来使用;
    /g表示一行上的替换所有匹配。

2016年1月28日星期四

ubuntu安装samba服务

apt-get install samba

vim /etc/samba/smb.conf,在最后加上以下配置,设置共享目录:
[share]
  path = your directory path
  browseable = yes
  writable = yes

添加samba用户:
useradd xxx
passwd xxx
smbpasswd -a xxx
如果已经有xxx用户,只需要smbpasswd -a即可。

重启samba服务:restart smbd,完成。

windows中开启ssh服务

提供思路,具体过程以后更新。

安装cygwin,安装过程中选择安装ssh,进行一些配置,完成。

Mac中解决LaTeX Error: File `lastpage.sty' not found问题

原因是在tex文件中使用了lastpage包,但是我只安装的basic版本的tex中没有这个包(link),所以需要另行安装。

在命令行中执行以下命令:
sudo tlmgr update --self
sudo tlmgr install lastpage

关于安装texlive-latex-extra,参考:link.

问题解决后,又遇到LaTeX Error: File `sectsty.sty' not found的问题,同理,在命令行中执行以下命令:
sudo tlmgr update --self  // 如果前面update过了这里不用再update
sudo tlmgr install sectsty

2016年1月27日星期三

Scala格式化数字输出

".3f".format(1.23456)  // 1.234

import java.text.DecimalFormat
val formatter = new DecimalFormat("#.###")
formatter.format(1)  // 1
formatter.format(1.34)  // 1.34
formatter.format(4.toFloat / 3)  // 1.333

2016年1月24日星期日

2016年1月22日星期五

在Sublime Text中使用Markdown

Markdown是一种简单的轻量级标记语言,一般用来写md文件。

在Sublime Text中使用Markdown
只需要安装Markdown Preview插件即可,ctrl+b 编译文件,编译完成后会生成一个html文件。

Markdown语言介绍
[ 转自http://www.jianshu.com/p/q81RER ]
标题:
# 一级标题
## 二级标题
### 三级标题
#### 四级标题
##### 五级标题
###### 六级标题
无序列表:
- 文本1
- 文本2
- 文本3
有序列表:
1. 文本1
2. 文本2
3. 文本3
链接:
[chenxiaoyu](http://jschenxiaoyu.blogspot.com)
在新标签页打开,只需要在后面再加上{:target="_blank"}即可。

图片:
![xxx](http://ww2.sinaimg.cn/square/83d79d5cjw8ew9f43d6pvj20hs0hs74y.jpg)
引用:
> 一盏灯, 一片昏黄; 一简书, 一杯淡茶。 守着那一份淡定, 品读属于自己的寂寞。 保持淡定, 才能欣赏到最美丽的风景! 保持淡定, 人生从此不再寂寞。
粗体(*)和斜体(**):
*一盏灯*, 一片昏黄;**一简书**, 一杯淡茶。 
表格:
| Tables        | Are           | Cool  |
| ------------- |:-------------:| -----:|
| col 3 is      | right-aligned | $1600 |
| col 2 is      | centered      |   $12 |
| zebra stripes | are neat      |    $1 |
TablesAreCool
col 3 isright-aligned$1600
col 2 iscentered$12
zebra stripesare neat$1

显示Latex:
![][1]
[1]: http://latex.codecogs.com/gif.latex?\prod{n_i}+1

分割线:
三个或更多的-_*,必须单独一行,可含空格
---

引用:
> 引用
>> 引用中的引用

代码格式:
`code`

代码块:
每行文字前加4个空格或者1个tab
和```效果一样

注释:
<!-- 注释 -->

root用户ssh登陆Permission denied, please try again.

vim /etc/ssh/sshd_config
将PermitRootLogin without-password改为PermitRootLogin yes
restart ssh,完成。

Mac和VirtualBox网络互访

在VirtualBox中打开偏好设置,选择网络,新建一个仅主机(Host-Only)网络,双击vboxnet0,设置网段,默认为192.168.56.1。

设置虚拟机,在网络选项中启用网卡2的网络连接,连接方式选择仅主机(Host-Only)适配器,确定,启动虚拟机。

2016年1月21日星期四

blade编译中collect2: ld returned 1 exit status问题

我是在虚拟机中编译的,遇到的问题比较奇怪,只有collect2: ld returned 1 exit status这个错误信息,没有其他提示。
原因是虚拟机的硬盘空间不够了,新加载了一个硬盘(参考链接:link),问题解决。

VirtualBox扩展虚拟机硬盘

参考链接:link.

选择相应的虚拟机,点击设置,选择左侧的存储,添加一个新的SATA控制器,启动虚拟机。

cd /dev,会发现多了一个sdb,fdisk  ./sdb,进入磁盘管理器。

输入命令p查看当前盘状态,输入命令n创建一个新的分区,有两个选项:e(扩展分区)和p(主分区),选择p分配区号(1到4中选)
Command (m for help): n
Partition type:
   p   primary (0 primary, 0 extended, 4 free)
   e   extended
Select (default p): p
Partition number (1-4, default 1):
Using default value 1
First sector (2048-20971519, default 2048):
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-20971519, default 20971519):
Using default value 20971519
输入w命令保存退出。

在硬盘上建立文件系统:mkfs -t ext4 /dev/sdb1

挂载文件系统,我直接挂在了/mnt目录下:mount /dev/sdb1 /mnt
设置开机自动挂载:vim /etc/fstab,在最后增加/dev/sdb1 /mnt ext4 defaults 0 0
完成。

Mac添加ll命令,并使ls命令结果着色

vim ~/.bashrc,在最后加上:
alias ls='ls -G'
alias ll='ls -l'
alias la='ls -a'

或者着色直接可以export CLICOLOR=1

vim ~/.bash_profile,在最后加上:
source ~/.bashrc
完成。

2016年1月20日星期三

解决blade编译时/usr/bin/ld: cannot find -ljvm的问题

解决方法:
系统没有找到libjvm.so文件,而该文件在/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/server目录下。如果没有,需要先安装jdk:apt-get install openjdk-7-jdk。

cd /usr/lib
ln -sv jvm/java-7-openjdk-amd64/jre/lib/amd64/server/libjvm.so libjvm.so
在/usr/lib中增加了libjvm.so,解决。

2016年1月19日星期二

2016年1月18日星期一

Source Insight中解决C++无法解析proto文件的问题

选择Options -> Preferences...,在Languages标签中双击C++ Language,点击Custom Parsing,然后Add一个Class,如图所示:
内容如下:
Namespace    ^package\w+\([a-zA-Z0-9_]+\)
Class    ^message\w+\([a-zA-Z0-9_]+\)
点击确定,re-parse project。
正则表达式参考:link.

选择Options -> Document Options...,在C++ Source File的File filter中增加*.proto,完成。

这个方法只能将就用,遇到 :: 不能解决。

现在看来,感觉也没什么卵用,直接把proto文件编译出来就可以了。

2016年1月15日星期五

Spark DataFrame的join操作

case class App(id: Int, name: String)
val data1 = sc.parallelize(Array((1, "a"), (2, "b"), (3, "c")))
val df1 = data.map { case (id, name) => App(id, name) }.toDF
val data2 = sc.parallelize(Array((1, "A"), (3, "B"), (5, "C")))
val df2 = data.map { case (id, name) => App(id, name) }.toDF

df1.show()
+---+----+
| id|name|
+---+----+
|  1|   a|
|  2|   b|
|  3|   c|
+---+----+

df2.show()
+---+----+
| id|name|
+---+----+
|  1|   A|
|  3|   B|
|  5|   C|
+---+----+

df1.join(df2)  // Cartesian join

df1.join(df2, "id")
+---+----+----+
| id|name|name|
+---+----+----+
|  1|   a|   A|
|  3|   c|   B|
+---+----+----+

df1.join(df2, df1("id") === df2("id")).show()
+---+----+---+----+
| id|name| id|name|
+---+----+---+----+
|  1|   a|  1|   A|
|  3|   c|  3|   B|
+---+----+---+----+

df1.join(df2, df1("id") === df2("id")).drop(df2("id")).show()
+---+----+----+
| id|name|name|
+---+----+----+
|  1|   a|   A|
|  3|   c|   B|
+---+----+----+

MySQL的基本操作

Please see this doc.

Spark SQL中DataFrame的几种写入模式

dataFrame.write.mode("xxx")进行设置

append
不改变表中已经存在记录,将新纪录写入。

overwrite
原来的记录全部删除,只有增加的记录。
举个例子:如果原来的表中有三个字段a, b, c,Overwrite的数据中只有两个字段a, b,那么原来c字段就没有了,慎用。

error
如果已经存在记录,抛出异常。

ignore
如果有已经存在的记录,DataFrame中的数据全部不会写入。

Spark SQL

关于Spark SQL,参考:link.

如果遇到 java.sql.SQLException: No suitable driver found for jdbc:mysql 问题,增加以下代码Class.forName("com.mysql.jdbc.Driver"),参考链接:link.

运行上一句代码时会出现 spark java.lang.ClassNotFoundException: com.mysql.jdbc.Driver 错误,需要设置jar包的路径指向mysql-connector-java-5.1.38-bin.jar:
./spark-submit --jars <path to jar>
如果在spark-shell或者standalone模式中运行,同样用--jars参数指定mysql-connector-java-5.1.38-bin.jar的路径。

如果不起作用的话,同时加入--driver-class-path <path to jar>设置。
如果再不行,再加上--conf spark.executor.extraClassPath=<path to jar>以及--conf spark.driver.extraClassPath=<path to jar>设置。参考链接:link.

2016年1月5日星期二

Spark读取jar包中的文件

直接附上我的示例代码:
package com.mobvoi.app.recommendation.data

import java.io.InputStream

import scala.io.Source.fromInputStream

trait AppNameData extends Serializable {
  @transient private val stream: InputStream = getClass.getResourceAsStream("/app_name.txt")

  private val appIdName = fromInputStream(stream).getLines.toArray

  /** Param for app id and app name map. */
  private[recommendation] val appIdNameMap = appIdName.map { x =>
    val str = x.split("   ")
    (str(0).trim, str(1).trim)
  }.toMap

  /** Param for app name and app id map. */
  private[recommendation] val appNameIdMap = appIdName.map { x =>
    val str = x.split("   ")
    (str(1).trim, str(0).trim)
  }.toMap
}