1、数据预处理
1、网站爬取数据,写为csv
2、添加表头
sed -i ‘1i\时报错:
sed: -i may not be used with stdin
mac中应该写为:【mac自带的sed命令,是基于bsd的,所以与Linux-like下常用的gnu不一样】
sed -i "" '1i\
insert value here
' filename.csv
3、处理为json
2、数据导入es集群
- 可参考这篇文章ElasticSearch(十二)——无文档ID的Json文件批量导入(Java/Python)
但是,之前
client = new PreBuiltTransportClient(settings).addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(addressMaster), transport));
中的InetSocketTransportAddress在6.3中已经不能使用,改为TransportAddress即可
public class JsonToES {
private static final Logger LOGGER = LoggerFactory.getLogger(OpenClose.class);
public void jsonToES(File[] files) {
Map<String, Object> hashMap = EsPropertiesUtils.getConf();
TransportClient client = OpenClose.getInstance(hashMap);
int idNum = 0;
for (File f : files) {
// 一、绝对路径读取文件
System.out.println(f.getAbsolutePath());
File file = new File(f.getAbsolutePath());
// 二、开始一行一行的写
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
BulkRequestBuilder bulkRequest = client.prepareBulk();
// Map<String, Object> valuesMap = new HashMap<>(64, 0.6f);
String line;
while ((line = br.readLine()) != null) {
bulkRequest.add(client.prepareIndex("taobao", "rates", Integer.toString(idNum)).setSource(line, XContentType.JSON));
// valuesMap.clear();
if (idNum % 20000 == 0) {
System.out.println("++++++++++++++++++++++++++++++++++++");
// 三、批量导入,与网速有关
bulkRequest.execute().actionGet();
}
idNum++;
System.out.println(idNum);
}
// 四、导入每个文件最后不足2000条的数据(但是必须得有数据,否则报错: no requests added)
// 查阅源码可知,可通过拿到父类requests属性,判断其size来解决[子类调用父类方法获得属性]
if (bulkRequest.request().requests().size() > 0) {
bulkRequest.get();
}
// 五、操作下一个文件
} catch (IOException e) {
LOGGER.error(":ERROR:堆栈信息====={}", e.getMessage());
}
}
OpenClose.closeClient(client);
}
public static void main(String[] args) {
JsonToES jsonToES = new JsonToES();
File file = new File("/Users/wanghai/shendeng_back/rates/");
// 目录下只有我需要读取的文件,故不再进行进一步处理
File[] files = file.listFiles();
long begin = System.currentTimeMillis();
jsonToES.jsonToES(files);
System.out.println("总耗时: " + (System.currentTimeMillis() - begin) / 1000 + "s");
}
}
3、优化
之前进行过一次优化实战,但是当时没有以多线程的形式进行优化。这里进行多线程提高写入速度的实战。
3-1、多线程读写文件小练习——写
先热身一下,以多线程的形式读写同一个文件,查看效率差异。
1、没用过Lock,打算不使用synchronized,尝试下Lock
3-1-1、synchronized与Lock的区别与使用
- 锁类型
- 可重入锁:在执行对象中所有同步方法不用再次获得锁
- 可中断锁:在等待获取锁过程中可中断
- 公平锁: 按等待获取锁的线程的等待时间进行获取,等待时间长的具有优先获取锁权利
- 读写锁:对资源读取和写入的时候拆分为2部分处理,读的时候可以多线程一起读,写的时候必须同步地写
synchronized的缺点有:
1)不能响应中断;
2)锁的释放由虚拟机来完成,不用人工干预,不过此即使缺点也是优点,优点是不用担心会造成死锁,缺点是由可能获取到锁的线程阻塞之后其他线程会一直等待,性能不高。
- 区别
synchronized与Lock的部分区别 |
类别 | synchronized | Lock |
---|---|---|
出身 | Java的关键字,在JVM层面实现了对临界资源的同步互斥访问 | 一个类,基于jdk层面实现 |
锁释放 | 1、已经获取锁的线程执行完同步代码,释放锁 2、线程执行发生异常,jvm会让线程释放锁 | 有加锁就必须有释放锁,finally中unLock()释放锁使Lock对更具灵活性 |
锁状态 | 无法判断 | 可以判断,tryLock(),获取锁的时候锁被占用就返回false |
锁类型 | 可重入 不可中断 非公平 | 可重入 可判断 可公平(默认非公平) |
more
使用场景:
TODO
4线程生产数据2线程数据写入实践
⚠️:该demo的多线程写磁盘的逻辑不好,有待修正,哈哈,但是3-2的测试还是有意义的;
⚠️:这个demo并没有生产意义,因为数据都是写入同一个文件,所以最终还是串行写入,磁头在各个磁盘来回寻道,也许不但不会提高效率,反而降低;
⚠️:生产中可以考虑不同线程读取不同的文件(但是磁头切换寻道可能耗时更多),然后处理数据的是别的线程,也就是获取数据和处理数据使用不同的线程,异步处理。
1、生产数据线程
public class WriteThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 2000000; i++) {
WriterQueue.getInstance().produce("线程:" + Thread.currentThread().getName() + "的第: " + i + " 条数据 " + UUID.randomUUID().toString() + " 123456789qwertyuiopasdfghjklzxcvbnm中文中文中文中文中文中文中文中文中文中文中文");
}
}
private void sleep(int millis) throws InterruptedException {
Thread.sleep(millis);
}
}
2、数据队列
Condtion接口:
- Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法,Condition中的signalAll()相当于Object的notifyAll()方法
- 例如下方代码所示,多线程写同一个缓冲区:当向队列中写入数据之后,唤醒”读线程”;当从队列读出数据之后,唤醒”写线程”;并且当缓冲区满的时候,”写线程”需要等待;当缓冲区为空时,”读线程”需要等待。
package<