HeLei Blog

不要因为走得太远,就忘记为什么而出发


  • 首页

  • 分类

  • 归档

  • 标签

  • 搜索
close
HeLei Blog

elasticsearch01

发表于 2017-04-21 | 分类于 ElasticSearch

##
Elasticsearch是一个基于Apache Lucene(TM)的开源搜索引擎。无论在开源还是专有领域,Lucene可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。
但是,Lucene只是一个库。想要使用它,你必须使用Java来作为开发语言并将其直接集成到你的应用中,更糟糕的是,Lucene非常复杂,你需要深入了解检索的相关知识来理解它是如何工作的。
Elasticsearch也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。
不过,Elasticsearch不仅仅是Lucene和全文搜索,我们还能这样去描述它:

  • 分布式的实时文件存储,每个字段都被索引并可被搜索
  • 分布式的实时分析搜索引擎
  • 可以扩展到上百台服务器,处理PB级结构化或非结构化数据
    而且,所有的这些功能被集成到一个服务里面,你的应用可以通过简单的RESTful API、各种语言的客户端甚至命令行与之交互。

可以用传统的关系数据库来作对比:

1
2
Relational DB -> Databases -> Tables -> Rows -> Columns
Elasticsearch -> Indices -> Types -> Documents -> Fields

如何安装

1.安装jdk,我自己机器上的是jdk7
2.下载安装包

1
wget https://download.elastic.co/elasticsearch/release/org/elasticsearch/distribution/tar/elasticsearch/2.3.4/elasticsearch-2.3.4.tar.gz

3.解压

1
tar -zxvf elasticsearch-2.3.4.tar.gz

4.启动服务

1
./bin/elasticsearch

5.测试是否成功

1
curl 'http://localhost:9200/?pretty'

如果输出下面的结果就大功告成了

1
2
3
4
5
6
7
8
{
"count" : 3,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
}
}

如何使用

###让我们建立一个员工目录

假设我们刚好在Megacorp工作,这时人力资源部门出于某种目的需要让我们创建一个员工目录,这个目录用于促进人文关怀和用于实时协同工作

###索引员工文档
所以为了创建员工目录,我们将进行如下操作:
为每个员工的文档(document)建立索引,每个文档包含了相应员工的所有信息。 每个文档的类型为employee。
employee类型归属于索引megacorp。 megacorp索引存储在Elasticsearch集群中。

我们看到path:/megacorp/employee/1包含三部分信息:
| 名字 | 说明 |
| ————- | ————- |
| megacorp | 索引名 |
| employee | 类型名 |
| 1 | 这个员工的ID |

使用RESTful API,通过9200端口的与Elasticsearch进行通信

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
curl -XPUT 'localhost:9200/megacorp/employee/1' -d '
{
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}'
curl -XPUT 'localhost:9200/megacorp/employee/2' -d '
{
"first_name" : "Jane",
"last_name" : "Smith",
"age" : 32,
"about" : "I like to collect rock albums",
"interests": [ "music" ]
}'
curl -XPUT 'localhost:9200/megacorp/employee/3' -d '
{
"first_name" : "Douglas",
"last_name" : "Fir",
"age" : 35,
"about": "I like to build cabinets",
"interests": [ "forestry" ]
}'

HeLei Blog

回顾C++(一)-STL中的clear

发表于 2017-04-17 | 分类于 C++

通常我们可能会写下这样的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
std::vector<int> v1;
for (int i = 0; i < 100; ++i)
{
v1.push_back(i);
}
cout<<"v1 before clear"<<endl;
cout<< "v1.size() = "<<v1.size()<<endl;
cout<< "v1.capacity() = "<<v1.capacity()<<endl;
v1.clear();
cout<<"v1 after clear"<<endl;
cout<< "v1.size() = "<<v1.size()<<endl;
cout<< "v1.capacity() = "<<v1.capacity()<<endl;
std::vector<int> v2;
for (int i = 0; i < 100; ++i)
{
v2.push_back(i);
}

运行结果

1
2
3
4
5
6
v1 before clear--------------
v1.size() = 100
v1.capacity() = 128
v1 after clear--------------
v1.size() = 0
v1.capacity() = 128

clear并没有释放掉内存,而仅仅是将size置为0,如果需要立即释放掉内存,可以用一个空的容器和其交换,修改后的代码如下:

1
2
3
4
5
6
7
8
cout<<"v2 before swap"<<endl;
cout<< "v2.size() = "<<v2.size()<<endl;
cout<< "v2.capacity() = "<<v2.capacity()<<endl;
vector<int>().swap(v2);
cout<<"v2 after swap--------------"<<endl;
cout<< "v2.size() = "<<v2.size()<<endl;
cout<< "v2.capacity() = "<<v2.capacity()<<endl;

运行结果

1
2
3
4
5
6
v2 before swap--------------
v2.size() = 100
v2.capacity() = 128
v2 after swap--------------
v2.size() = 0
v2.capacity() = 0

c++11中增加了新的方法shrink_to_fit,可以释放掉多余的内存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
std::vector<int> v3;
for (int i = 0; i < 100; ++i)
{
v3.push_back(i);
}
cout<<"v3 before shrink_to_fit--------------"<<endl;
cout<< "v3.size() = "<<v3.size()<<endl;
cout<< "v3.capacity() = "<<v3.capacity()<<endl;
v3.shrink_to_fit();
cout<<"v3 after shrink_to_fit--------------"<<endl;
cout<< "v3.size() = "<<v3.size()<<endl;
cout<< "v3.capacity() = "<<v3.capacity()<<endl;

运行结果

1
2
3
4
5
6
v3 before shrink_to_fit--------------
v3.size() = 100
v3.capacity() = 128
v3 after shrink_to_fit--------------
v3.size() = 100
v3.capacity() = 100

Question?
不理解这个方法的作用,设置capacity的本意是预留内存,下次插入元素时不用涉及耗时的内存分配,这样下次插入元素肯定会触发重新分配内存。

HeLei Blog

回顾C++(二)-STL中的sort

发表于 2017-04-17 | 分类于 C++

相等 or 等价

STL充满了比较对象是否有同样的值。比如,当你用find来定位区间中第一个有特定值的对象的位置,find必须可以比较两个对象,看看一个的值是否与另一个相等。同样,当你尝试向set中插入一个新元素时,set::insert必须可以判断那个元素的值是否已经在set中了。

find算法和set的insert成员函数是很多必须判断两个值是否相同的函数的代表。但它们以不同的方式完成,find对“相同”的定义是相等,基于operator==。set::insert对“相同”的定义是等价,通常基于operator<。等价是基于在一个有序区间中对象值的相对位置。等价一般在每种标准关联容器(比如,set、multiset、map和multimap)的一部分——排序顺序方面有意义。两个对象x和y如果在关联容器c的排序顺序中没有哪个排在另一个之前,那么它们关于c使用的排序顺序有等价的值。set的默认比较函数是less,而默认的less简单地对Widget调用operator<,所以w1和w2关于operator<有等价的值如果下面表达式为真:

1
2
3
(w1 < w2) // w1 < w2时它非真
&& // 而且
(w2<w1) // w2 < w1时它非真

HeLei Blog

lucence-01

发表于 2017-04-11

lucence简介

Lucene不是一个完整的全文索引应用,而是是一个用Java写的全文索引引擎工具包,它可以方便的嵌入到各种应用中实现针对应用的全文索引/检索功能。

Lucene的作者:Lucene的贡献者Doug Cutting是一位资深全文索引/检索专家,曾经是V-Twin搜索引擎(Apple的Copland操作系统的成就之一)的主要开发者,后在Excite担任高级系统架构设计师,目前从事于一些INTERNET底层架构的研究。他贡献出的Lucene的目标是为各种中小型应用程序加入全文检索功能。

Lucene的发展历程:早先发布在作者自己的www.lucene.com,后来发布在SourceForge,2001年年底成为APACHE基金会jakarta的一个子项目:http://jakarta.apache.org/lucene/

HeLei Blog

generate

发表于 2017-03-23
HeLei Blog

boost_coroutine

发表于 2017-03-23 | 分类于 协程

两个函数如何并发执行?

函数并发执行

执行转移机制

执行转移机制

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
31
32
33
#include <iostream>
#include <boost/coroutine/all.hpp>
typedef boost::coroutines::asymmetric_coroutine< void >::pull_type pull_coro_t;
typedef boost::coroutines::asymmetric_coroutine< void >::push_type push_coro_t;
void foo(push_coro_t & sink)
{
std::cout << "1";
sink();
std::cout << "2";
sink();
std::cout << "3";
sink();
std::cout << "4";
}
int main(int argc, char * argv[])
{
{
pull_coro_t source(foo);
while (source)
{
std::cout << "-";
source();
}
}
std::cout << "\nDone" << std::endl;
return 0;
}

运行输出

1
1-2-3-4

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
31
32
33
34
35
36
#include <iostream>
#include <boost/coroutine/all.hpp>
using namespace std;
typedef boost::coroutines::asymmetric_coroutine< int >::pull_type pull_coro_t1;
typedef boost::coroutines::asymmetric_coroutine< int >::push_type push_coro_t1;
void foo1(push_coro_t1& sink1)
{
cout<<"1";
sink1(10);
cout<<"2";
sink1(20);
cout<<"3";
sink1(30);
cout<<"4";
sink1(40);
}
int main(int argc, char const *argv[])
{
{
pull_coro_t1 source1(foo1);
while (source1)
{
int ret = source1.get();
cout<<"ret: "<<ret<<endl;
source1();
}
}
cout<<"\nDone"<<endl;
return 0;
}

运行输出

1
2
3
4
1ret: 10
2ret: 20
3ret: 30
4ret: 40

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
31
32
33
34
35
36
37
#include <iostream>
#include <boost/coroutine/all.hpp>
using namespace std;
typedef boost::coroutines::asymmetric_coroutine< int >::pull_type pull_coro_t1;
typedef boost::coroutines::asymmetric_coroutine< int >::push_type push_coro_t1;
void foo1(pull_coro_t1& sink1)
{
cout<<"1 "<<source1.get();
sink1();
cout<<"2 "<<source1.get();
sink1();
cout<<"3 "<<source1.get();
sink1();
cout<<"4 "<<source1.get();
sink1();
}
int main(int argc, char const *argv[])
{
{
push_coro_t1 source1(foo1);
int c = 0;
while (source1)
{
++c;
source1();
}
}
cout<<"\nDone"<<endl;
return 0;
}
HeLei Blog

IO模型介绍

发表于 2017-03-22 | 分类于 network

阻塞io模型

阻塞io模型

非阻塞io模型

非阻塞io模型

io复用模型

io复用模型

信号驱动io模型

信号驱动io模型

异步io模型

异步io模型

多啰嗦几句:
a. 阻塞和非阻塞描述的对象是函数,指调用这个函数后是否会block进程/线程。
b. 同步/异步描述的是执行IO操作的主体是谁,同步是由用户进程自己去执行最终的IO操作。异步是用户进程自己不关系实际IO操作的过程,只需要由内核在IO完成后通知它既可,由内核进程来执行最终的IO操作。

HeLei Blog

数据发送过程

发表于 2017-03-20 | 分类于 network

tcp发送

tcp发送过程

  • 从写一个TCP套接字的write调用成功返回仅表示可以使用原来的应用进程缓冲区,并不表明对端的TCP或应用进程已接受到数据
  • 通过getsockopt得到默认的发送缓冲区的大小为16384B。
  • 非阻塞的send时,发送缓冲区满后会阻塞;非阻塞的send时,会返回EAGAIN。

udp发送

udp发送过程

  • udp是不可靠的,不会保存应用进程数据的一个副本,因此没有真正的发送缓冲区(数据被发送后,这个副本就被数据链路层丢弃)。udp的write调用成功返回表示所写的数据报或其所有片段已加入数据链路层的输出队列(如果空间不够,应用进程也不会知道)。
  • 通过getsockopt得到默认的接收缓冲区的大小为87380B。
HeLei Blog

TCP状态机分析(一)

发表于 2017-03-09 | 分类于 network

tcp状态机

tcp状态机

建立连接过程

流程图
三次握手流程图

tcpdump抓包(listen port 1234)

1
sudo tcpdump -i lo tcp port 1234 and host 127.0.0.1

客户端代码

1
2
3
4
if(connect(sockfd,(struct sockaddr *)&server,sizeof(server))==-1){
printf("connect()error\n");
exit(1);
}

服务端代码

1
2
3
4
5
6
7
8
9
if((connectfd = accept(listenfd,(struct sockaddr*)&client,&addrlen))==-1) {
perror("accept()error\n");
exit(1);
}
else
{
printf("Yougot a connection from cient's ip is %s, prot is %d\n",inet_ntoa(client.sin_addr),htons(client.sin_port));
}
sleep(30);

tcpdump抓包
tcpdump三次握手

netstat查看连接状态

1
netstat -apn |grep 1234

established status

关闭连接过程

为验证CLOSE_WAIT状态,服务端accpet后sleep,客户单立即调用close

流程图
四次挥手流程图

客户端代码

1
close(sockfd);

服务端代码

1
sleep(30);

tcpdump抓包
tcpdump四次挥手

netstat查看连接状态

1
netstat -apn |grep 1234

established status

服务端sleep时间到后,此时客户端已close,read返回0后,服务端也调用close,进入TIME_WAIT状态。

为什么需要TIME_WAIT?
a. 当发起关闭一方的最后一个ack丢失后,对方会重传FIN,如果直接关闭连接,发起发就收不到重传FIN。
b. 当被动关闭一方的最后一个FIN包超时重传,如果没有TIME_WAIT状态而且此时发起方用相同的ip和port建立了新的连接,这时候会收到这个重传的包,并认为他是新连接的包,就会导致严重错误。

HeLei Blog

nginx内存管理

发表于 2017-02-26 | 分类于 Nginx
1…678
He Lei

He Lei

c/c++/python | redis | recommend algorithm | search engine

75 日志
16 分类
3 标签
GitHub Weibo
© 2018 He Lei
由 Hexo 强力驱动
主题 - NexT.Pisces