Swoole处理Tcp粘包问题(面向过程)

TCP通信特点

  • TCP 是流式协议没有消息边界,客户端向服务器端发送一次数据,可能会被服务器端分成多次收到。客户端向服务器端发送多条数据。服务器端可能一次全部收到。
  • 保证传输的可靠性,顺序。
  • TCP拥有拥塞控制,所以数据包可能会延后发送。

TCP粘包

介绍

TCP 粘包是指发送方发送的若干包数据 到 接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。

原因

发送方:发送方需要等缓冲区满才发送出去,造成粘包
接收方:接收方不及时接收缓冲区的包,造成多个包接收
下图为tcp协议在传输数据的过程:
Tcp协议传输数据过程.jpg

swoole处理粘包

  • EOF结束协议:
    EOF切割需要遍历整个数据包的内容,查找EOF,因此会消耗大量CPU资源。上手比较简单

  • 固定包头+包体协议
    长度检测协议,只需要计算一次长度,数据处理仅进行指针偏移,性能非常高

重现TCP粘包问题

服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

//创建Server对象,监听 127.0.0.1:9501端口
$server = new Swoole\Server("127.0.0.1", 9501);

//监听连接进入事件
$server->on('Connect', function ($server, $fd) {
echo "Client: Connect.\n";
});

//监听数据接收事件
$server->on('Receive', function ($server, $fd, $from_id, $data) {

echo '接到消息'.$data.PHP_EOL;

});

//监听连接关闭事件
$server->on('Close', function ($serv, $fd) {
echo "Client: Close.\n";
});

//启动服务器
$server->start();

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
$client = new swoole_client(SWOOLE_SOCK_TCP);
//连接到服务器
if (!$client->connect('127.0.0.1', 9501, 0.5)) die("connect failed.");



//向服务器发送数据


for ($i = 0; $i <= 100; $i++) $client->send('12345678');

//从服务器接收数据
$data = $client->recv();
if (!$data) die("recv failed.");



//关闭连接
$client->close();

如下图:此时数据并不是完整的数据
服务端.png

固定包头+包体协议

服务端

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
38
39
40
41
42
<?php

//创建Server对象,监听 127.0.0.1:9501端口
$server = new Swoole\Server("127.0.0.1", 9501);

$server->set(
[
'open_length_check' => true, // 打开包长检测特性
'package_max_length' => 1024 * 1024 * 2, // 包最大长度
'package_length_type' => 'N', // 长度值的类型
'package_length_offset' => 0, // 从第几个字节开始计算长度
'package_body_offset' => 4, // 长度值在包头的第几个字节
]
);

//监听连接进入事件
$server->on('Connect', function ($server, $fd) {
echo "Client: Connect.\n";
});

//监听数据接收事件
$server->on('Receive', function ($server, $fd, $from_id, $data) {
//解包 去掉包头数据
$body = unpack('N',$data);
$content = substr($data,4,reset($body)); // 这里的 4 的计算公式 N 为32字节序 1字节等于8bit 32 / 8 = 4
var_dump($content);

//回复客户端消息 如果客户端设置了 open_length_check 也需要将数据打包
$message = 'this is Server !';
$send = pack('N',strlen($message)).$message;


$server->send($fd,$send);
});

//监听连接关闭事件
$server->on('Close', function ($serv, $fd) {
echo "Client: Close.\n";
});

//启动服务器
$server->start();

客户端

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
<?php
$client = new swoole_client(SWOOLE_SOCK_TCP);
$client->set(
[
'open_length_check' => true, // 打开包长检测特性
'package_max_length' => 1024 * 1024 * 2, // 包最大长度
'package_length_type' => 'N', // 长度值的类型
'package_length_offset' => 0, // 从第几个字节开始计算长度
'package_body_offset' => 4, // 长度值在包头的第几个字节
]
);
//连接到服务器
if (!$client->connect('127.0.0.1', 9501, 0.5)) die("connect failed.");


$content = 'Hello world';
$body = pack('N', strlen($content)) . $content;

//向服务器发送数据
if (!$client->send($body)) die("send failed.");


//从服务器接收数据
$data = $client->recv();
if (!$data) die("recv failed.");


//解包 去掉包头数据
$body = unpack('N',$data);
$content = substr($data,4,reset($body)); // 这里的 4 的计算公式 N 为32字节序 1字节等于8bit 32 / 8 = 4
var_dump($content);

//关闭连接
$client->close();

swoole-version 4.4.12


Swoole TCP和UDP(同步和异步)

Tcp: 舔狗行为 可靠 先连接然后发消息等待回复

Udp: 渣男行为 不可靠 不需要建立连接 通信不需要一直保持

  • tcp服务端

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <?php

    //创建Server对象,监听 127.0.0.1:9501端口
    $serv = new Swoole\Server("127.0.0.1", 9501);

    //监听连接进入事件
    $serv->on('Connect', function ($serv, $fd) {
    echo "Client: Connect.\n";
    });

    //监听数据接收事件
    $serv->on('Receive', function ($serv, $fd, $from_id, $data) {
    $serv->send($fd, "Server: ".$data);
    });

    //监听连接关闭事件
    $serv->on('Close', function ($serv, $fd) {
    echo "Client: Close.\n";
    });

    //启动服务器
    $serv->start();
  • tcp同步客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
$client = new swoole_client(SWOOLE_SOCK_TCP);

//连接到服务器
if (!$client->connect('127.0.0.1', 9501, 0.5))
{
die("connect failed.");
}
//向服务器发送数据
if (!$client->send("hello world"))
{
die("send failed.");
}
//从服务器接收数据
$data = $client->recv();
if (!$data)
{
die("recv failed.");
}
echo $data.PHP_EOL;
//关闭连接
$client->close();

echo '这里是同步客户端!'.PHP_EOL;
  • tcp异步客户端(只能在cli模式下运行)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

$client = new Swoole\Async\Client(SWOOLE_SOCK_TCP);

$client->on("connect", function($cli) {
$cli->send("GET / HTTP/1.1\r\n\r\n");
});
$client->on("receive", function($cli, $data){
echo "Receive: $data";
$cli->send(time()."\n");
sleep(1);
});
$client->on("error", function($cli){
echo "error\n";
});
$client->on("close", function($cli){
echo "Connection close\n";
});
$client->connect('127.0.0.1', 9501);

echo '这里是异步客户端'.PHP_EOL;
  • udp服务端
1
2
3
4
5
6
7
8
9
10
11
12
<?php
//创建Server对象,监听 127.0.0.1:9502端口,类型为SWOOLE_SOCK_UDP
$serv = new Swoole\Server("127.0.0.1", 9502, SWOOLE_PROCESS, SWOOLE_SOCK_UDP);

//监听数据接收事件
$serv->on('Packet', function ($serv, $data, $clientInfo) {
$serv->sendto($clientInfo['address'], $clientInfo['port'], "Server ".$data);
var_dump($clientInfo);
});

//启动服务器
$serv->start();
  • udp客户端
1
2
3
4
5
6
<?php
$client = new Swoole\Client(SWOOLE_SOCK_UDP);

$client->sendto('127.0.0.1',9502,'哈哈哈');
$result = $client->recv();
echo $result;

swoole-version 4.4.12


消息中间件Kafka - PHP操作使用Kafka

PHP使用Kafka

我们需要安装libkafkardkafka

安装libkafka

  1. 下载

    去GitHub上克隆下来

    git clone https://github.com/edenhill/librdkafka.git

  2. 安装

cd librdkafka/

`./configure && make && make install`

安装成功界面 没有报错就是安装成功

![14c1ce5d9719d16db1f2de5e9eed9553.png](https://img-blog.csdnimg.cn/20190320100758703.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMzIwMjgx,size_16,color_FFFFFF,t_70)

安装rdkafka

  1. 下载

    git clone https://github.com/arnaud-lb/php-rdkafka

    cd php-rdkafka/

  2. 为php安装扩展

在php-rdkafka这个目录下

`phpize`

然后会生成源代码安装的脚本

把php-config的位置改成自己php-config的位置

` ./configure --with-php-config=/usr/local/php/bin/php-config`

编译安装

`make && make install`

成功后会出现一个文件夹

![70c28ed68f37346a84abe96a2fe03aae.png](https://img-blog.csdnimg.cn/20190320100828577.png)

这个位置就是保存的我们刚刚安装的扩展

进入该目录

`cd /usr/local/php/lib/php/extensions/no-debug-non-zts-20170718/`

会发现出现个rdkafka.so文件

![2bb11d41b5e08b42a3fad4fc181eb791.png](https://img-blog.csdnimg.cn/20190320100957658.png)

修改php.ini文件加入  这里的路径就是写自己rdkafka.so文件的路径

`extension=/usr/local/php/lib/php/extensions/no-debug-non-zts-20170718/rdkafka.so `
重启php

php-m

出现rdkafka就是安装成功

![fe40f168197be21fb00db6d06428df24.png](https://img-blog.csdnimg.cn/20190320101008302.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMzIwMjgx,size_16,color_FFFFFF,t_70)

php操作kafka

运行前先开启我们的zookeeper和kafka 上篇文章有如何开启

  1. 运行producer
    kafka默认端口9092 vim producer.php
     <?php
        $rk = new RdKafka\Producer();
        $rk->setLogLevel(LOG_DEBUG);
        $rk->addBrokers("ip:9092");       
        $topic = $rk->newTopic("test");
        $topic->produce(RD_KAFKA_PARTITION_UA, 0, "要发送的消息");
               
               
    
  2. 运行consumer
    vim consumer.php
     <?php
        $rk = new RdKafka\Consumer();
        $rk->setLogLevel(LOG_DEBUG);
        $rk->addBrokers("ip");
        $topic = $rk->newTopic("test");
        $topic->consumeStart(0, RD_KAFKA_OFFSET_BEGINNING);
        while(true){
            sleep(1);
            $msg = $topic->consume(0, 1000);
            if ($msg) {
                echo $msg->payload, "\n";
            }          
        }    
        
        
    
    开启两个窗口一个运行consumer 一个运行producer php consumer.php
    php producer.php会发现我们已经简单的会使用kafka了。

消息中间件Kafka - 介绍及安装

Kafka介绍

优势

  • 高吞吐量:非常普通的硬件Kafka也可以支持每秒数百万的消息
  • 支持通过Kafka服务器和消费机集群来区分消息
  • 支持Hadoop并行数据加载

关键概念

  • Broker:Kafka集群中的一台或多台服务器统称为broker。
  • Topic:Kafka处理的消息源(feeds of messages)的不同分类。
  • Partition:Topic物理上的分组,一个topic可以分为多个partition,每个partition是一个有序的队列。partition中的每条消息都会被分配一个有序的id(offset)。
  • Message:消息,是通信的基本单位,每个producer可以向一个topic(主题)发布一些消息。
  • Producers:消息和数据生产者,向Kafka的一个topic发布消息的过程叫做producers。
  • Consumers:消息和数据的消费者,订阅topics并处理其发布的消息的过程叫做consumers。

9443d8a422fad65faca5bcfe843dc5f1.png

安装

  1. 下载
    先安装jdk 然后jdk的安装方式在elasticsearch的安装文章中有,这里就不写了
    kafka官网 wget https://www-us.apache.org/dist/kafka/2.1.1/kafka_2.11-2.1.1.tgz 解压 tar -xzvf kafka_2.11-2.1.1.tgz
  1. 修改配置文件

    cd kafka_2.11-2.1.1/config

    zookeeper.properties 是zookeeper的配置文件,默认端口号2181,可不做修改

    server.properties 是kafka配置文件,将 zookeeper.connect 这行 改为自己的zookeeper地址和端口号

    修改完成之后 返回kafka主目录

    cd ..

  2. 运行zookeeper和kafka

    运行zookeeper

    bin/zookeeper-server-start.sh config/zookeeper.properties

    不要关闭此窗口 再开一个新窗口 重新进入kafka目录

    运行kafka

    bin/kafka-server-start.sh config/server.properties

  3. 运行producer和consumer

    跟上步操作一样 不要关闭窗口 重新开 重新进入kafka目录

    创建一个topic为test

    把ip和port改为自己zookeeper的

    bin/kafka-topics.sh --create --zookeeper ip:port --replication-factor 1 --partitions 1 --topic test

    运行producer

    bin/kafka-console-producer.sh --broker-list ip:port --topic test

    跟上步操作一样 不要关闭窗口 重新开 重新进入kafka目录

    运行consumer

    bin/kafka-console-consumer.sh --bootstrap-server ip:port --topic test --from-beginning

    然后在producer发送信息 会发现 consumer的窗口会出现你发送的消息

    d4b0ffa28a974f98c733bb3e054b83ac.png
    8d4e50024a47893502c701ecea979d27.png

消息队列 - 应用场景

消息队列

相关概念

消息队列中间件时分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题。实现高性能,高可用,可伸缩和最终一致性架构。是大型分布式系统不可缺少的中间件。

异步处理
  • 场景说明:用户注册成功后,发送注册邮件,再发送注册短信。
  • 串行方式:将注册信息写入数据库成功后,向用户发送邮件,再发送注册短信,将结果返回客户端。
  • 并行方式:将注册信息写入数据库成功后,发送注册邮件的同时,发送注册短信,以上三个任务完成后,返回给客户端。
  • 消息队列:将注册信息写入数据库成功后,注册信息写入消息队列,发送邮件和短信的消费者异步读取消息队列,写入消息队列即将返回给客户端。
    19ce1bd87b7cc498e92733342f4d9f01.png
应用解耦
  • 场景说明:用户下单后,订单系统需要通知库存系统。
  • 传统方式:订单系统调用库存系统的接口。
  • 消息队列->
  • 订单系统*:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功。
  • 库存系统*:订阅下单的消息,采用拉/推的方式,获取下单信息,库存系统根据下单信息,进行库存操作。
    5828d130146f855b2730f9e404537d5f.png
流量削锋
  • 场景说明:秒杀活动,一般会因为流量过大,导致流量暴增。
  • 传统方式:服务端突然接受来自前端的大量订单请求
  • 消息队列:在应用前端加入消息队列->
  1. 用户的请求,服务器接收后,首先写入消息队列。假如消息队列长度超过最大数量,则直接抛弃用户请求或跳转到错误页面
  2. 秒杀业务根据消息队列中的请求信息,再做后续处理
    bf97f667722518fa1bb367b4ce3959fc.png
日志处理
  • 解决大量日志传输的问题
  • 日志采集客户端,负责日志数据采集,写入消息队列
  • 消息队列,负责日志数据的接收,存储和转发
  • 日志处理应用:订阅并消费消息队列中的日志数据
    abb22f7464ce76ffb6ff86a2da88efb4.png
消息通讯
  • 点对点消息队列,或者聊天室
    440b22e6237a9a48f1599c6dea10fee8.png
  • 客户端A和客户端B使用同一队列,进行消息通讯
  • 客户端A,客户端B,客服端N订阅同一主题,进行消息发布和接收
    7abde092c2b5ab7cecc9b23b4dd3bc2d.png

主要产品

目前在生成环境,使用较多的消息队列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ等

ElasticSearch全文检索引擎-使用

ElasticSearch使用

手册官网

es-docs
es-php-docs

索引

  1. 创建索引

    vim createindex.json

     {
         "settings": {
             "refresh_interval": "5s",
             "number_of_shards": 1,
             "number_of_replicas": 0
         },
         "mappings": {
             "_default_": {
                 "_all": {
                     "enabled": true
                 }
             }
         },
         "products": {
             "dynamic": false,
             "properties": {
                 "productid": {
                     "type": "long"
                 },
                 "title": {
                     "type": "string",
                     "index": "analyzed",
                     "analyzer": "ik"
                 },
                 "descr": {
                     "type": "string",
                     "index": "analyzed",
                     "analyzer": "ik"
                 }
             }
         }
     }
    

    具体的字段意思手册上都有

    创建

    curl -XPOST "http://ip:port/shop" -d'@createindex.json

    这里的shop就是我们要设置的索引名称 可以自定义
    products 是 索引的type类型 可以自定义

  2. 添加数据

    curl -XPUT "http://119.23.51.33:9200/shop/products/1" -d'{"productid":1,"title":"这是一个商品的标题","descr":"这是一个商品的描述"}'

`curl -XPUT "http://ip:port/shop/products/2?pretty" -d'{"productid":2,"title":"这是一部手机","descr":"这是一个苹果手机的描述信息"}'`

url地址后面的整值要跟文章id一致

pretty就是 Elasticsearch美化输出(pretty-print)JSON响应以便更加容易阅读。
  1. 搜索数据

    vim search.json

      {
         "query": {
             "multi_match": {
                 "query": "苹果",
                 "fields": [
                     "title",
                     "descr"
                 ]
             }
         },
         "highlight": {
             "pre_tags": [
                 "<em>"
             ],
             "post_tags": [
                 "</em>"
             ],
             "fields": {
                 "title": {},
                 "descr": {}
             }
         }
     }
     
    

    query 要查询的关键字
    fields 哪些字段需要被查询
    highlight 被查询出来的关键字 进行一些改变 相当于高亮显示
    pre_tags 标签开始 post_tags标签结束

    测试

    curl -XGET "http://ip:port/shop/_search?pretty" -d"@search.json"

elasticsearch-jdbc

将数据库的数据同步到elasticsearch

  1. 下载

    wget http://xbib.org/repository/org/xbib/elasticsearch/importer/elasticsearch-jdbc/2.3.4.0/elasticsearch-jdbc-2.3.4.0-dist.zip

    unzip elasticsearch-jdbc-2.3.4.0-dist.zip

  1. 修改配置

    cd elasticsearch-jdbc-2.3.4.0/bin

    为了防止出错 先备份一下

    cp mysql-blog.sh mysql-blog.sh.bak

    vim mysql-blog.sh

    将 echo 下的内容替换成以下内容

     {
         "type" : "jdbc",
         "jdbc" : {
             "url" : "jdbc:mysql://localhost:3306/good",
             "user" : "root",
             "password" : "1C292567e208",
             "sql" : "select productid,title,descr,productid as _id from test",
             "index" : "shop",
             "type" : "products",
             "elasticsearch" : {
                  "cluster" : "search",
                  "host" : "ip",
                  "port" : 9300
             }   
         }
     }
    

    url 是我们的数据库 good是库名 对哪个库进行操作
    user password 用户名和密码
    sql语句 就是 执行后 把查询出来的数据添加到es中
    这里呢productid as _id 是因为es的唯一标识是根据_id生成的
    index 我们刚刚创建的索引名称
    products 是索引type类型
    cluster 是我们es配置文件中的项目名称
    host port 分别为ip和端口号 port为9300 这个地方不可以改

  2. 运行

    ./mysql-blog.sh

    curl -XGET "http://119.23.51.33:9200/shop/_search?pretty"

    可以看到数据库的内容被添加进去了

    但是修改数据库内容 或者 添加内容 es却不会改变 下面怎么改变呢

  3. 监控 实时同步

     {
         "type" : "jdbc",
         "jdbc" : {
             "url" : "jdbc:mysql://localhost:3306/good",
             "schedule" : "0 0-59 0-23 ? * *",
             "user" : "root",
             "password" : "1C292567e208",
             "sql" : [{
                     "statement": "select productid,title,descr,productid as _id from test where updatetime > unix_timestamp(?) ",
                     "parameter": ["$metrics.lastexecutionstart"]}
                 ],
             "index" : "shop",
             "type" : "products",
             "metrics": {
                 "enabled" : true
             },
             "elasticsearch" : {
                  "cluster" : "search",
                  "host" : "ip",
                  "port" : 9300
             }   
         }
     }
     
    

    这时需要一个字段去判断 那就是我们数据的修改时间
    parameter 里面的内容 就是获取上次脚本执行时间
    sql 的where条件 就是判断 修改时间大于上次脚本执行时间 就属于新数据

    重新执行下脚本 就可以了

    怎么用php操作呢

    现在有好多框架的轮子

    或者直接看es-php-docs

    php框架:

    laravel-elasticsearch
    yii2-elasticsearch
    去GitHub上查找就行

ElasticSearch全文检索引擎-安装

ElasticSearch安装

安装JDK

  1. 下载rpm包

    wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "https://download.oracle.com/otn-pub/java/jdk/8u201-b09/42970487e3af4f5aa5bca3f542482c60/jdk-8u201-linux-x64.rpm"

  2. rpm安装

    rpm -ivh jdk-8u201-linux-x64.rpm
    安装成功后测试 java javac java -version 命令都能使用

安装ElasticSearch

  1. 官网
    ElasticSearch

  2. 下载
    这里我下载的2.4.6版本

    wget https://download.elastic.co/elasticsearch/release/org/elasticsearch/distribution/rpm/elasticsearch/2.4.6/elasticsearch-2.4.6.rpm

  3. 安装ElasticSearch

    yum install elasticsearch-2.4.6.rpm

  4. 修改配置文件

    vim /etc/elasticsearch/elasticsearch.yml

    cluster.name: my-application这行取消注释 并且改为自己的应用名称
    node.name: node-1 这行也一样 改为自己的节点名称
    为了方便操作 应用名称改为 search 节点名称为 master
    network.host: 192.168.0.1 取消注释 改为 0.0.0.0
    http.port: 9200 取消注释就行 可以自行修改端口号
    切记 取消注释后 首字母前面不能有空格 不然启动会报错

  5. 运行ElasticSearch

    service elasticsearch start
    浏览器访问ip+端口号 如果出现界面证明 成功

安装ik中文分词

  1. ik分词地址

    ik

  2. 安装git和maven

    如果有的话跳过此步

    安装git
    yum install -y git

    下载maven包
    wget https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.5.4/binaries/apache-maven-3.5.4-bin.tar.gz

    解压到指定目录
    tar -xzvf apache-maven-3.5.4-bin.tar.gz -C /usr/local

    进入指定目录
    cd /usr/local/

    创建软连接
    ln -s apache-maven-3.5.4 maven

    编辑文件 添加maven环境变量
    vim /etc/profile

    在文件末尾添加以下代码
    MAVEN_HOME=//usr/local/maven
    export MAVEN_HOME
    export PATH=${PATH}:${MAVEN_HOME}/bin

    运行命令
    source /etc/profile

    mvn -v
    出现版本 安装maven成功

  3. 安装ik分词
    克隆
    git clone https://github.com/medcl/elasticsearch-analysis-ik.git

    根据elasticsearch版本号切换相对应的ik分词版本号 这里es是2.4.6 相对应是1.10.6

    克隆好之后进入该目录
    cd elasticsearch-analysis-ik/

    切换版本
    git checkout tags/v1.10.6

    执行
    mvn package

    执行成功后会在 target/releases/ 目录下生成一个插件包 进入该目录
    cd target/releases/

    复制到es的插件目录下解压
    cp elasticsearch-analysis-ik-1.10.6.zip /usr/share/elasticsearch/plugins/

    进入目录
    cd /usr/share/elasticsearch/plugins/

    解压
    unzip elasticsearch-analysis-ik-1.10.6.zip

    为了方便管理 新建个文件夹 把刚刚解压出来的文件移动进去
    mkdir ik
    mv ./* ik

    重启elasticsearch
    service elasticsearch restart

    测试下
    curl -XPOST "http://ip:port/_analyze?analyzer=ik&pretty" -d '这是一个商品的标题'


ElasticSearch和ik分词安装成功

ElasticSearch全文检索引擎-介绍

全文检索

种将文件种或者数据库中所有文本与检索项匹配的文字资料检索方法。对全文数据的检索

数据分类:

  • 结构化数据

      行数据,存储在数据库里,可以用二维表结构来逻辑表达实现的数据 
      能够用数据或统一的结构加以表示 
      数字、符号去表示
    
  • 非结构化数据

      无法用数字或统一的结构表示
      文本、图像、声音、网页
      结构化数据属于非结构化数据
      非结构化数据即为全文数据
    
两种方法
  • 顺序扫描法

      将数据库中所有的内容挨个扫描
    
  • 索引扫描法

      全文检索的基本思路,也即将非结构化数据中的一部分信息提取出来,重新组织,使其变得有一定结构,然后对此有一定结构的数据进行搜索,从而达到搜索相对较快的目的。
    
全文检索过程
  • 索引创建
      索引保存的是一个词元,对应文档的id
      索引只会创建一次
    

如何创建:

  1.     一些要索引的原文档(Document)
    
  2.     将原文档传给分词组件(Tokenizer)
    
  3.     将得到的词元(Token)传给语言处理组件(LinguisticProcessor)
    
  4.  将得到的词(Term)传给索引组件(Indexer)
    
         
    
  • 搜索索引
  1.     用户输入查询语句
    
  2.     对查询语句进行词法分析,语法分析,及语言处理
    
  3.     搜索索引,得到符号文档
    

全文检索引擎

全文检索引擎是目前广泛应用的主流搜索引擎。
它的工作原理是计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。

相关产品

Lucene,Sphinx,Xapian,Nutch,DataparkSearch…

ElasticSearch

ElasticSearch是一个基于Apache Lucene(TM)的开源搜索引擎。无论在开源还是专有领域,Lucene可以被认为是迄今为止最先进、性能最好的,功能最全的搜索引擎库。

为什么要选择ElasticSearch

ElasticSearch也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。

分布式的实时文件存储,每个字段都被索引可被搜索
分布式的实时分析搜索引擎
可以扩展到上百台服务器,处理PB级结构化或非结构化数据

所有功能都集成在一个服务里面,可以通过RESTful API、各种语言的客户端甚至命令行与之交互
上手容易,提供了很多合理的缺省值,开箱即用,学习成本低
可免费下载、使用和修改 配置灵活

Laravel使用repository模式

什么是Repository模式?Repository 模式是架构模式,在设计架构时,才有参考价值; Repository 模式主要是封装数据查询和存储逻辑; Repository 模式实际用途:更换、升级 ORM 引擎,不影响业务逻辑; Repository 模式能提高测试效率,单元测试时,用 Mock 对象代替实际的数据库存取,可以成倍地提高测试用例运行速度。

详细了解 https://blog.csdn.net/ZuoAnYinXiang/article/details/80711936

REPOSITORY模式是怎样工作的呢?Repository 是一个独立的层,介于领域层与数据映射层(数据访问层)之间。它的存在让领域层感觉不到数据访问层的存在,它提供一个类似集合的接口提供给领域层进行领域对象的访问。Repository 是仓库管理员,领域层需要什么东西只需告诉仓库管理员,由仓库管理员把东西拿给它,并不需要知道东西实际放在哪。

详细了解 http://www.jquerycn.cn/a\_17077

当controller不使用Repository模式 ,在controller的各个方法中存在花式的数据库操作(这是非常糟糕的),如果需求变更,重写将变得非常困难。

Laravel如何部署

Laravel 5 Repositories用于抽象数据层,使我们的应用程序更易于维护。

安装

composer require prettus/l5-repository

laravel部署

laravel>=5.5
在框架的config/app.php中的providers数组添加如下代码:‘

Prettus\Repository\Providers\RepositoryServiceProvider::class,

发布配置

php artisan vendor:publish --provider "Prettus\Repository\Providers\RepositoryServiceProvider"

命令

要生成模型所需的所有内容,请运行以下命令:

php artisan make:entity Post

这将创建Controller,Validator,Model,Repository,Presenter和Transformer类。它还将创建一个新的服务提供程序,用于将Eloquent Repository与其相应的Repository Interface绑定。要加载它,只需将其添加到AppServiceProvider @ register方法:

$this->app->register(RepositoryServiceProvider::class);

自定义使用方法

在你的控制器中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
namespace App\Http\Controllers;

use App\PostRepository;

class PostsController extends Controller {

/**
* @var PostRepository
*/
protected $repository;

public function __construct(PostRepository $repository){
$this->repository = $repository;
}
public function index(){
return $this->repository->all();
}
}

更多操作:GitHub : https://github.com/andersao/l5-repository/tree/3.0-develop