微信小程序+人脸识别详解

识别过程借助于百度AI,服务器依旧是 SSM 框架

服务端代码
  • Base64Util
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.parking.util;

public class Base64Util {
    private static final char last2byte = (char)Integer.parseInt("00000011", 2);
    private static final char last4byte = (char)Integer.parseInt("00001111", 2);
    private static final char last6byte = (char)Integer.parseInt("00111111", 2);
    private static final char lead6byte = (char)Integer.parseInt("11111100", 2);
    private static final char lead4byte = (char)Integer.parseInt("11110000", 2);
    private static final char lead2byte = (char)Integer.parseInt("11000000", 2);
    private static final char[] encodeTable = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};

    public Base64Util() {
    }

    public static String encode(byte[] from) {
        StringBuilder to = new StringBuilder((int)((double)from.length * 1.34D) + 3);
        int num = 0;
        char currentByte = 0;

        int i;
        for(i = 0; i < from.length; ++i) {
            for(num %= 8; num < 8; num += 6) {
                switch(num) {
                case 0:
                    currentByte = (char)(from[i] & lead6byte);
                    currentByte = (char)(currentByte >>> 2);
                case 1:
                case 3:
                case 5:
                default:
                    break;
                case 2:
                    currentByte = (char)(from[i] & last6byte);
                    break;
                case 4:
                    currentByte = (char)(from[i] & last4byte);
                    currentByte = (char)(currentByte << 2);
                    if(i + 1 < from.length) {
                        currentByte = (char)(currentByte | (from[i + 1] & lead2byte) >>> 6);
                    }
                    break;
                case 6:
                    currentByte = (char)(from[i] & last2byte);
                    currentByte = (char)(currentByte << 4);
                    if(i + 1 < from.length) {
                        currentByte = (char)(currentByte | (from[i + 1] & lead4byte) >>> 4);
                    }
                }

                to.append(encodeTable[currentByte]);
            }
        }

        if(to.length() % 4 != 0) {
            for(i = 4 - to.length() % 4; i > 0; --i) {
                to.append("=");
            }
        }

        return to.toString();
    }
}

此工具类用于将图片文件转换为 Base64 字符串的形式

  • FileUtil
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.parking.util;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileUtil {
    public FileUtil() {
    }

    public static byte[] readFileByBytes(String filePath) throws IOException {
        File file = new File(filePath);
        if(!file.exists()) {
            throw new FileNotFoundException(filePath);
        } else {
            ByteArrayOutputStream bos = new ByteArrayOutputStream((int)file.length());
            BufferedInputStream in = null;

            try {
                in = new BufferedInputStream(new FileInputStream(file));
                short bufSize = 1024;
                byte[] buffer = new byte[bufSize];

                int len1;
                while(-1 != (len1 = in.read(buffer, 0, bufSize))) {
                    bos.write(buffer, 0, len1);
                }

                byte[] var7 = bos.toByteArray();
                byte[] var9 = var7;
                return var9;
            } finally {
                try {
                    if(in != null) {
                        in.close();
                    }
                } catch (IOException var14) {
                    var14.printStackTrace();
                }

                bos.close();
            }
        }
    }
}

此工具类用于处理图片文件

- HttpUtil 
package com.parking.util;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.Map;


public class HttpUtil {

    public static String post(String requestUrl, String accessToken, String params)
            throws Exception {
        String contentType = "application/x-www-form-urlencoded";
        return HttpUtil.post(requestUrl, accessToken, contentType, params);
    }

    public static String post(String requestUrl, String accessToken, String contentType, String params)
            throws Exception {
        String encoding = "UTF-8";
        if (requestUrl.contains("nlp")) {
            encoding = "GBK";
        }
        return HttpUtil.post(requestUrl, accessToken, contentType, params, encoding);
    }

    public static String post(String requestUrl, String accessToken, String contentType, String params, String encoding)
            throws Exception {
        String url = requestUrl + "?access_token=" + accessToken;
        return HttpUtil.postGeneralUrl(url, contentType, params, encoding);
    }

    public static String postGeneralUrl(String generalUrl, String contentType, String params, String encoding)
            throws Exception {
        URL url = new URL(generalUrl);

        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("POST");

        connection.setRequestProperty("Content-Type", contentType);
        connection.setRequestProperty("Connection", "Keep-Alive");
        connection.setUseCaches(false);
        connection.setDoOutput(true);
        connection.setDoInput(true);


        DataOutputStream out = new DataOutputStream(connection.getOutputStream());
        out.write(params.getBytes(encoding));
        out.flush();
        out.close();

        connection.connect();

        Map<String, List<String>> headers = connection.getHeaderFields();
 
        for (String key : headers.keySet()) {
            System.err.println(key + "--->" + headers.get(key));
        }
        
        BufferedReader in = null;
        in = new BufferedReader(
                new InputStreamReader(connection.getInputStream(), encoding));
        String result = "";
        String getLine;
        while ((getLine = in.readLine()) != null) {
            result += getLine;
        }
        in.close();
        System.err.println("result:" + result);
        return result;
    }
}
  • 人脸识别登录
    @ResponseBody
    @RequestMapping(value = "/FaceLogins", method = RequestMethod.POST)
    public Object loginFace(@RequestParam("files") CommonsMultipartFile file,
            HttpServletRequest request, HttpServletResponse response)
            throws IOException {

        String resMsg = "";
        String path = null;
        

        try {

            long startTime = System.currentTimeMillis();

            System.out.println("fileName:" + file.getOriginalFilename());
            path = request.getSession().getServletContext()
                    .getRealPath("upload");
            System.out.println("path:" + path);

            String fileTyle = ".png";// 全部以png格式进行保存
            String newFileName = "tempLogin" + fileTyle;
            System.out.println(newFileName);
            System.out.println(fileTyle);
            File newFile = new File(path, newFileName);

            file.transferTo(newFile);
            long endTime = System.currentTimeMillis();
            System.out.println("运行时间:" + String.valueOf(endTime - startTime)
                    + "ms");
            resMsg = "1";


        } catch (FileNotFoundException e) {

            e.printStackTrace();
            resMsg = "0";
        }

        System.out.println(resMsg);
        
        
        if(resMsg.equals("1")){
            // 进行人脸识别
            String username = (String)faceVerify(path+"\\tempLogin.png");
            
            System.out.println("username"+username);
            
            
            return username;
        }
        
        
        return 0;       
        

    }


    public Object faceVerify(String pathFile) {
        // 请求url
        String url = "https://aip.baidubce.com/rest/2.0/face/v3/search";
        try {

            byte[] bytes = FileUtil
                    .readFileByBytes(pathFile);
            String image = Base64Util.encode(bytes);

            Map<String, Object> map = new HashMap<String, Object>();
            map.put("image", image);
            map.put("image_type", "BASE64");
            map.put("liveness_control", "NORMAL");
            map.put("group_id_list", "park_sys");
            map.put("quality_control", "NONE");

            String param = GsonUtils.toJson(map);

            // 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间,
            // 客户端可自行缓存,过期后重新获取。
            String accessToken = "5555555555";//请自行获取令牌

            String result = HttpUtil.post(url, accessToken, "application/json",
                    param);
            System.out.println(result);

            // 处理返回JSON
            JSONObject json;
            json = JSONObject.fromObject(result);
            
            //获取识别状态
            String code = json.getString("error_code");
            String msg  = json.getString("error_msg");
            
                        
            
            //人脸识别成功
            if (code.equals("0")&&msg.equals("SUCCESS")){
                JSONArray JArray = json.getJSONObject("result").getJSONArray("user_list");
                json = JSONObject.fromObject(JArray.get(0).toString());
                System.out.println(json.getString("user_id"));
                return json.getString("user_id");
            }else{
                return "Error";
            }
            
            
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

实现思路是从微信客户端获取上传的文件图片,并调用百度人脸识别接口与人脸库图片进行匹配识别,获取返回的用户信息,调用Service方法进行判断是否成功登录。

微信小程序

  faceLogin:function(){

    var flagTemp = '';

    var that = this;
    wx.chooseImage({
      count: 1, // 默认9
      sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
      sourceType: ['camera'],
  

      success: function (res) {
        wx.showLoading({
          title: '识别中',
        })
        var tempFilePaths = res.tempFilePaths
        wx.uploadFile({
          url: Api1,//使用人脸识别接口
          //method: 'GET',
          filePath: tempFilePaths[0],
          header: {
            'content-type': 'application/json' // 默认值
          },
          name: 'files',          
          success: function (res) {
            that.flagTemp = res.data;
            console.log("flag" + that.flagTemp);
          if (res.data != 0) {
            var uUsername = that.flagTemp;
            console.log(uUsername)

            user = {
              uUsername: uUsername,              
            }

            wx.request({          
              url: Api2,
              method: 'GET',
              data: user,
              header: {
                "Content-Type": "application/x-www-form-urlencoded"  // 默认值
              },
              success: function (res) {
                wx.hideLoading();
                app.globalData.userInfo = res.data;
                console.log(res.data);
                if (res.data != 0) {
                  wx.switchTab({
                    url: '../index/index'
                  })
                } else {
                  wx.showModal({
                    title: '识别失败',
                    content: '请重新识别',
                    showCancel: false, //不显示取消按钮
                    confirmText: '确定'
                  })
                }
              }
            })
          }
          
          }
        })
      }
    })

  },

只允许用户调用摄像头进行拍照,并调用文件上传API将图片上传进客户端获取用户名后在使用request方法对SpringMVC的Action进行用户查询,实现登录功能。
注意:如果不使用wx.request进行数据申请,是取不到服务端返回的JSON数据的

微信小程序之生物识别用法

生物识别有三个接口

1、wx.checkIsSupportSoterAuthentication 用来获取本机支持的生物识别方式(人脸、指纹、声纹)

2、wx.startSoterAuthentication 进行生物认证

3、wx.checkIsSoterEnrolledInDevice 检测是否录入生物信息

wxml代码

 bindtap="checkIsFingerPrint">检测是否可以指纹识别
 bindtap="checkIsFacial">检测是否可以人脸识别
 bindtap="HaveFingerPrint">该设备是否录入指纹
 bindtap="FingerPrint">识别指纹

js代码

Page({

  /**
   * 页面的初始数据
   */
  data: {
    isfingerPrint : false,    //可否使用指纹识别  默认false
    isfacial: false,          //可否使用人脸识别  默认false
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    var that = this
    //查看支持的生物认证   比如ios的指纹识别   安卓部分机器是不能用指纹识别的
    wx.checkIsSupportSoterAuthentication({
      success(res) {
        for (var i in res.supportMode){
          if (res.supportMode[i] == 'fingerPrint'){
            console.log("支持指纹识别", res.supportMode[i]);
            that.setData({
              isfingerPrint : true
            })
          } else if (res.supportMode[i] == 'facial'){
            console.log("支持人脸识别", res.supportMode[i]);
          }
        }
      }
    })
  },
  //是否可以指纹识别
  checkIsFingerPrint:function(){
    var boole = this.data.isfingerPrint
    var txt = "不可以使用指纹识别"
    if (boole) {
      txt = "可以使用指纹识别"
    }
    show("提示",txt,false);
  },
  //是否可以人脸识别
  checkIsFacial: function () {
    var boole = this.data.isfacial
    var txt = "不可以使用人脸识别"
    if (boole){
      txt = "可以使用人脸识别"
    }
    function SUCC() {
      console.log("用户点击确定")
    }

    function FAIL() {
      console.log("用户点击取消")
    }

    show("提示", txt, true,SUCC,FAIL);
  },

  //进行指纹识别
  FingerPrint: function(){
    wx.startSoterAuthentication({
      requestAuthModes: ['fingerPrint'],
      challenge: '123456',
      authContent: '请用指纹',
      success(res) {
        console.log("识别成功",res)
        show("提示", "识别成功", false);
      },
      fail(res){
        console.log("识别失败",res)
        show("提示", "识别失败", false);
      }
    })


  },
  //是否有指纹
  HaveFingerPrint:function(){
    wx.checkIsSoterEnrolledInDevice({
      checkAuthMode: 'fingerPrint',
      success(res) {
        if (res.isEnrolled == 1){
          show("提示", "有指纹", false);
        } else if (res.isEnrolled == 0){
          show("提示", "无指纹", false);
        }
      },
      fail(res){
        show("提示", "异常", fail);
      }
    })
  }
})


/**
 * 显示提示信息
 * tit 提示的标题
 * msg 提示的内容
 * q   是否有取消按钮(布尔值)
 * succ 用户点击确定的回调(非必须)
 * fail 用户点击取消的回调(非必须)
 *
 */
function show(tit,msg,q,succ,fail){
  wx.showModal({
    title: tit,
    content: msg,
    showCancel:q,
    success: function (res) {
      if (res.confirm) {
        if (succ){
          succ();
        }
      } else if (res.cancel) {
        if (fail) {
          fail();
        }
      }
    }
  })
}

微信小程序 wx.showToast()详细用法

wx.showToast接口只提供了两种icon【success和loading】展示形式,但是在实际开发中并不满足的。这里可以通过加image:’图片路径’

onLoad: function (options) {

    wx.showToast({

      title:”成功”,

      icon: ‘loading…’,//图标,支持”success”、”loading” 

      image: ‘/images/logo.png’,//自定义图标的本地路径,image 的优先级高于 icon

      duration: 2000,//提示的延迟时间,单位毫秒,默认:1500 

      mask: false,//是否显示透明蒙层,防止触摸穿透,默认:false 

      success:function(){},

      fail:function(){},

      complete:function(){}

    })

  },

Trying to create too many scroll contexts. Must be less than or equal to: [500].

从es上查询数据报错如下

Trying to create too many scroll contexts. Must be less than or equal to: [500]. This limit can be set by changing the [search.max_open_scroll_context] setting.
1
解决办法,用linux curl命令执行,默认search.max_open_scroll_context是500,改成5000

curl -X PUT http://127.0.0.1:9200/_cluster/settings -H ‘Content-Type: application/json’ -d'{
“persistent” : {
“search.max_open_scroll_context”: 4000
},
“transient”: {
“search.max_open_scroll_context”: 4000
}
}

Linux下启动,停止,重启Nginx、Mysql、PHP

LINUX启动Nginx的命令:

一、查询是否启动

[root@jiang php-fpm.d]# ps -ef | grep nginx

root     25225     1  0 19:26 ?        00:00:00 nginx: master process /app/nginx/sbin/nginx

www      25229 25225  0 19:26 ?        00:00:00 nginx: worker process

root     25247 19431  0 19:30 pts/0    00:00:00 grep nginx

二、启动

[root@jiang php-fpm.d]# /app/nginx/sbin/nginx

[root@jiang php-fpm.d]# ps -ef | grep nginx  

root     25192     1  0 19:22 ?        00:00:00 nginx: master process /app/nginx/sbin/nginx

www      25193 25192  0 19:22 ?        00:00:00 nginx: worker process

root     25195 19431  0 19:22 pts/0    00:00:00 grep nginx

三、停止

从容停止Nginx:

kill -QUIT 主进程号

[root@jiang php-fpm.d]# kill -QUIT 19513

[root@jiang php-fpm.d]# ps -ef | grep nginx

root     25190 19431  0 19:22 pts/0    00:00:00 grep nginx

快速停止Nginx:

kill -TERM 主进程号

[root@jiang php-fpm.d]# kill -TERM 25192

[root@jiang php-fpm.d]# ps -ef | grep nginx

root     25203 19431  0 19:23 pts/0    00:00:00 grep nginx

[root@jiang php-fpm.d]# 

强制停止Nginx:

kill -9 主进程号  

[root@jiang php-fpm.d]# kill -9 25205

[root@jiang php-fpm.d]# ps -ef | grep nginx

www      25206     1  0 19:24 ?        00:00:00 nginx: worker process

root     25210 19431  0 19:24 pts/0    00:00:00 grep nginx

四、重启

[root@jiang php-fpm.d]# /app/nginx/sbin/nginx -s reload

[root@jiang php-fpm.d]# 

LINUX启动MYSQL的命令:

一、启动

[root@jiang host]# service mysqld startStarting MySQL..                                           [  OK  ]

或者

[root@jiang host]# /etc/init.d/mysqld startStarting MySQL..                                           [  OK  ]

二、停止

[root@jiang host]# service mysqld stopShutting down MySQL..                                      [  OK  ]

或者

[root@jiang host]# /etc/init.d/mysqld stopShutting down MySQL.                                       [  OK  ]

三、重启

[root@jiang host]# service mysqld restartShutting down MySQL..                                      [  OK  ]

Starting MySQL..                                           [  OK  ]

或者

[root@jiang host]# /etc/init.d/mysqld restartShutting down MySQL..                                      [  OK  ]

Starting MySQL..                                           [  OK  ]

四、查看mysql是否启动

[root@jiang host]# service mysqld status

MySQL running (24110)                                      [  OK  ]

[root@jiang host]# ps aux | grep mysqld

LINUX启动PHP的命令:

service php-fpm restart

停止PHP:

[root@jiang host]# pkill php-fpm查看9000端口:

[root@jiang host]# netstat -lnt | grep 9000

[root@jiang host]# 

启动PHP:

[root@jiang sbin]# /app/php7.2/sbin/php-fpm查看9000端口:

[root@jiang sbin]# netstat -tunlp | grep 9000

tcp        0      0 127.0.0.1:9000              0.0.0.0:*                   LISTEN

Ubuntu系统下用Crontab命令定时执行PHP文件详解

Crontab命令。这个是系统定时命令,作用是定时的去执行一些任务。包含一些系统级别的任务,当然用户也可以直接借用该命令来实现自己的一些计划任务。

该命令一般跟随系统启动,我们可以使用一下命令来查看是否cron是否启动

?

1Pgrep cron

如果启动了,会返回一个进程id

Crontab文件一般存放于/etc目录下。我们使用,crontab -e来编辑cron任务。(第一次用这个命令,会让你选择文本编辑器)

打开cron文件,注意观察最后一行 m h dom…这里简要介绍一下它的意思。

  • m:分钟,0-59
  • h:小时,0-23
  • dom:日期,1-31
  • mon:月份,1-12
  • dow:星期,0-6,0为星期天
  • command:命令

这里,我们应该已经知道其大概的用法了。我们只要在对应的位置填写上我们需要的数字日期,就可以使用它来表示:在某月(mon)的某天(dom)或者星期几(dow)的几点(h,24小时制)几分(m)执行某个命令(command)。

举个栗子:

?

* * * * * php /path/to/your/cron.php5个星号分别代表定时指定每分、小时、日、月、周。
 * 19 * * * php /var/www/cron/crontab.php讲第二个参数h填写为19,则表示每天的下午7点执行crontab.php。 
* * * * * php /path/to/your/cron.php   每隔一分钟执行一次任务
 0 * * * * php /path/to/your/cron.php   
  每小时的0点执行一次任务,比如6:00,10:00
 6,10 * 2 * * php /path/to/your/cron.php   每个月2号,每小时的6分和10分执行一次任务
 */3,*/5 * * * * php /path/to/your/cron.php  每隔3分钟或5分钟执行一次任务,比如10:03,10:05,10:06

在这个例子中,我们看到不仅有数字还有星号和/等等符号。这些符号可以让定时更加的灵活。

  • *(星号):表示任意值,在相应位置填写*,可以代表任意执行。比如h为*,则为任意的小时
  • ,(逗号):表示一个部分填写多个值,比如在m位置填写1,5代表1分钟或5分钟时候
  • /(斜杠):表示每隔多久,比如在h部分填写*/2表示每隔2个小时,*/3表示每隔3个小时,
  • */1和*无区别,所以可以省略。这里可以想想,*/2表示能被2整除的时间就好理解了。

使用你的编辑器,保存->退出之后。重新启动cron任务。在每天的相应时间即可看到效果。

下面我们就先来说说PHP开发中,我常用的两种。

第一种:直接调用PHP文件

这种比较简单,我们新建一个php文件。向一个文件插入一些简单的日期内容。

?

#!/usr/bin/php -q<?php $file = “/var/www/”.date(“H”).”_”.date(“i”).”_”.date(“s”).”.txt”;file_put_contents($file,date(“Y-m-d”)); ?>

注意:这种直接调用PHP文件需要在PHP文件最上方加入#!/usr/bin/php -q代码,而第二种方式(接下来会讲),是直接访问链接,通过Apache来解析PHP,这种PHP脚本则不需要加这段代码。

?

1 6 * * * /path/to/your/cron.php每天的上午6点01分,执行cron.php文件

第二种:通过访问URL链接定时。

访问URL链接需要借助于浏览器来实现。我们选择Lynx浏览器,Lynx浏览器是一款轻便的web浏览器,使用于大部分Unix 和Linux系统环境。安装命令:

?

sudo apt-get install lynx

然后就可以和直接访问PHP文件类似的定时访问URL啦。

?

* * * * * lynx -dump http://weiya.me/index.php

注意这个地址最好用绝对地址,包含“http://”的完整url。

Elasticsearch 三种分页方式

from + size 浅分页
“浅”分页可以理解为简单意义上的分页。它的原理很简单,就是查询前20条数据,然后截断前10条,只返回10-20的数据。这样其实白白浪费了前10条的查询。

GET test_dev/_search
{
“query”: {
“bool”: {
“filter”: [
{
“term”: {
“age”: 28
}
}
]
}
},
“size”: 10,
“from”: 20,
“sort”: [
{
“timestamp”: {
“order”: “desc”
},
“_id”: {
“order”: “desc”
}
}
]
}

其中,from定义了目标数据的偏移值,size定义当前返回的数目。默认from为0,size为10,即所有的查询默认仅仅返回前10条数据。

在这里有必要了解一下from/size的原理:
因为es是基于分片的,假设有5个分片,from=100,size=10。则会根据排序规则从5个分片中各取回100条数据数据,然后汇总成500条数据后选择最后面的10条数据。

做过测试,越往后的分页,执行的效率越低。总体上会随着from的增加,消耗时间也会增加。而且数据量越大,就越明显!

scroll 深分页
from+size查询在10000-50000条数据(1000到5000页)以内的时候还是可以的,但是如果数据过多的话,就会出现深分页问题。

为了解决上面的问题,elasticsearch提出了一个scroll滚动的方式。
scroll 类似于sql中的cursor,使用scroll,每次只能获取一页的内容,然后会返回一个scroll_id。根据返回的这个scroll_id可以不断地获取下一页的内容,所以scroll并不适用于有跳页的情景。

GET test_dev/_search?scroll=5m
{
“query”: {
“bool”: {
“filter”: [
{
“term”: {
“age”: 28
}
}
]
}
},
“size”: 10,
“from”: 0,
“sort”: [
{
“timestamp”: {
“order”: “desc”
},
“_id”: {
“order”: “desc”
}
}
]
}

scroll=5m表示设置scroll_id保留5分钟可用。
使用scroll必须要将from设置为0。
size决定后面每次调用_search搜索返回的数量
然后我们可以通过数据返回的_scroll_id读取下一页内容,每次请求将会读取下10条数据,直到数据读取完毕或者scroll_id保留时间截止:

GET _search/scroll
{
“scroll_id”: “DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAJZ9Fnk1d……”,
“scroll”: “5m”
}

注意:请求的接口不再使用索引名了,而是 _search/scroll,其中GET和POST方法都可以使用。

scroll删除
根据官方文档的说法,scroll的搜索上下文会在scroll的保留时间截止后自动清除,但是我们知道scroll是非常消耗资源的,所以一个建议就是当不需要了scroll数据的时候,尽可能快的把scroll_id显式删除掉。

清除指定的scroll_id:

DELETE _search/scroll/DnF1ZXJ5VGhlbkZldGNo…..

清除所有的scroll:

DELETE _search/scroll/_all

search_after 深分页
scroll 的方式,官方的建议不用于实时的请求(一般用于数据导出),因为每一个 scroll_id 不仅会占用大量的资源,而且会生成历史快照,对于数据的变更不会反映到快照上。

search_after 分页的方式是根据上一页的最后一条数据来确定下一页的位置,同时在分页请求的过程中,如果有索引数据的增删改查,这些变更也会实时的反映到游标上。但是需要注意,因为每一页的数据依赖于上一页最后一条数据,所以无法跳页请求。

为了找到每一页最后一条数据,每个文档必须有一个全局唯一值,官方推荐使用 _uid 作为全局唯一值,其实使用业务层的 id 也可以。

GET test_dev/_search
{
“query”: {
“bool”: {
“filter”: [
{
“term”: {
“age”: 28
}
}
]
}
},
“size”: 20,
“from”: 0,
“sort”: [
{
“timestamp”: {
“order”: “desc”
},
“_id”: {
“order”: “desc”
}
}
]
}

使用search_after必须要设置from=0。
这里我使用timestamp和_id作为唯一值排序。
我们在返回的最后一条数据里拿到sort属性的值传入到search_after。
使用sort返回的值搜索下一页:

GET test_dev/_search
{
“query”: {
“bool”: {
“filter”: [
{
“term”: {
“age”: 28
}
}
]
}
},
“size”: 10,
“from”: 0,
“search_after”: [
1541495312521,
“d0xH6GYBBtbwbQSP0j1A”
],
“sort”: [
{
“timestamp”: {
“order”: “desc”
},
“_id”: {
“order”: “desc”
}
}
]

}
原文:https://blog.csdn.net/andybegin/article/details/83864171
版权声明:本文为博主原创文章,转载请附上博文链接!

Python连接MySQL数据库

Python标准数据库接口为Python DB-API, Python DB-API为开发人员提供了数据库应用 编程接口。

Python 数据库接口支持非常多的数据库,你可以选择适合你项目的数据库:

  • GadFly
  • mSQL
  • MySQL
  • PostgreSQL
  • Microsoft SQL Server 2000 Informix
  • Interbase Oracle Sybase

你可以访问Python数据库接口及API查看详细的支持数据库列表。

不同的数据库你需要下载不同的DB API模块,例如你需要访问Oracle数据库和Mysql数据,你需要下载Oracle和MySQL数据库模块。

DB-API是一个规范。它定义了一系列必须的对象和数据库存取方式, 以便为各种各样的底层数据库系统和多种多样的数据库接口程序提供一致的访问接口。

Python的DB-API,为大多数的数据库实现了接口,使用它连接各数据库后,就可以用相同 的方式操作各数据库。

Python DB-API使用流程:

  1. 引入API模块。
  2. 获取与数据库的连接。
  3. 执行SQL语句和存储过程。
  4. 关闭数据库连接。

1. MySQLdb

MySQLdb是用于Python链接Mysql数据库的接口,它实现了Python 数据库API规范V2.0,基于MySQL C API上建立的。

安装

直接使用pip进行安装,在此之前需要安装一些系统依赖包。

  • CentOS 

yum install gcc python-devel mysql-devel zlib-devel openssl-devel

  • Ubuntu 

sudo apt-get install libmysqlclient-dev libmysqld-dev python-dev python-setuptools

安装完依赖,直接使用pip安装,MySQLdb模块的名字在pip上叫MySQL-python。

pip install MySQL-python

常用函数

Python DB API 2.0 对事务提供了两个方法:

  • commit() 提交
  • rollback() 回滚

cursor用来执行命令的方法:

  • callproc(self, procname, args) 用来执行存储过程,接收的参数为存储过程名和参数列表,返回值为受影响的行数
  • execute(self, query, args) 执行单条sql语句,接收的参数为sql语句本身和使用的参数列表,返回值为受影响的行数
  • executemany(self, query, args) 执行单挑sql语句,但是重复执行参数列表里的参数,返回值为受影响的行数
  • nextset(self) 移动到下一个结果集

cursor用来接收返回值的方法:

  • fetchall(self) 接收全部的返回结果行.
  • fetchmany(self, size=None) 接收size条返回结果行.如果size的值大于返回的结果行的数量,则会返回cursor.arraysize条数据.
  • fetchone(self) 返回一条结果行.
  • rowcount 这是一个只读属性,并返回执行execute() 方法后影响的行数。
  • scroll(self, value, mode=’relative’) 移动指针到某一行; 如果mode=’relative’,则表示从当前所在行移动value条,如果 mode=’absolute’,则表示从结果集的第一行移动value条.

实例

#!/usr/bin/env python# -*- coding: utf-8 -*-import MySQLdb as mdb

# 连接数据库

conn = mdb.connect(‘localhost’, ‘root’, ‘root’)

# 也可以使用关键字参数

conn = mdb.connect(host=’127.0.0.1′, port=3306, user=’root’, passwd=’root’, db=’test’, charset=’utf8′)

# 也可以使用字典进行连接参数的管理

config = {

    ‘host’: ‘127.0.0.1’,

    ‘port’: 3306,

    ‘user’: ‘root’,

    ‘passwd’: ‘root’,

    ‘db’: ‘test’,

    ‘charset’: ‘utf8’

}

conn = mdb.connect(**config)

# 如果使用事务引擎,可以设置自动提交事务,或者在每次操作完成后手动提交事务conn.commit()

conn.autocommit(1)    # conn.autocommit(True)

# 使用cursor()方法获取操作游标

cursor = conn.cursor()# 因该模块底层其实是调用CAPI的,所以,需要先得到当前指向数据库的指针。

try:

    # 创建数据库

    DB_NAME = ‘test’

    cursor.execute(‘DROP DATABASE IF EXISTS %s’ %DB_NAME)

    cursor.execute(‘CREATE DATABASE IF NOT EXISTS %s’ %DB_NAME)

    conn.select_db(DB_NAME)

    #创建表

    TABLE_NAME = ‘user’

    cursor.execute(‘CREATE TABLE %s(id int primary key,name varchar(30))’ %TABLE_NAME)

    # 插入单条数据

    sql = ‘INSERT INTO user values(“%d”,”%s”)’ %(1,”jack”)

    # 不建议直接拼接sql,占位符方面可能会出问题,execute提供了直接传值

    value = [2,’John’]

    cursor.execute(‘INSERT INTO test values(%s,%s)’,value)

    # 批量插入数据

    values = []

    for i in range(3, 20):

        values.append((i,’kk’+str(i)))

    cursor.executemany(‘INSERT INTO user values(%s,%s)’,values)

    # 查询数据条目

    count = cursor.execute(‘SELECT * FROM %s’ %TABLE_NAME)

    print ‘total records: %d’ %count

    print ‘total records:’, cursor.rowcount

    # 获取表名信息

    desc = cursor.description

    print “%s %3s” % (desc[0][0], desc[1][0])

    # 查询一条记录

    print ‘fetch one record:’

    result = cursor.fetchone()

    print result

    print ‘id: %s,name: %s’ %(result[0],result[1])

    # 查询多条记录

    print ‘fetch five record:’

    results = cursor.fetchmany(5)

    for r in results:

        print r

    # 查询所有记录

    # 重置游标位置,偏移量:大于0向后移动;小于0向前移动,mode默认是relative

    # relative:表示从当前所在的行开始移动; absolute:表示从第一行开始移动

    cursor.scroll(0,mode=’absolute’)

    results = cursor.fetchall()

    for r in results:

        print r

    cursor.scroll(-2)

    results = cursor.fetchall()

    for r in results:

        print r

    # 更新记录

    cursor.execute(‘UPDATE %s SET name = “%s” WHERE id = %s’ %(TABLE_NAME,’Jack’,1))

    # 删除记录

    cursor.execute(‘DELETE FROM %s WHERE id = %s’ %(TABLE_NAME,2))

    # 如果没有设置自动提交事务,则这里需要手动提交一次

    conn.commit()except:

    import traceback

    traceback.print_exc()

    # 发生错误时会滚

    conn.rollback()finally:

    # 关闭游标连接

    cursor.close()

    # 关闭数据库连接

    conn.close()

查询时返回字典结构

MySQLdb默认查询结果都是返回tuple,通过使用不同的游标可以改变输出格式,这里传递一个cursors.DictCursor参数。

import MySQLdb.cursors

conn = MySQLdb.connect(host=’localhost’, user=’root’, passwd=’root’, db=’test’, cursorclass=MySQLdb.cursors.DictCursor)

cursor = conn.cursor()

cursor.execute(‘select * from user’)

r = cursor.fetchall()print r# 当使用位置参数或字典管理参数时,必须导入MySQLdb.cursors模块

# 也可以用下面的写法import MySQLdb as mdb

conn  = mdb.connect(‘localhost’, ‘root’, ‘root’, ‘test’)

cursor = conn.cursor(cursorclass=mdb.cursors.DictCursor)

cursor.execute(‘select * from user’)

r = cursor.fetchall()print r

MySQLdb取回大结果集的技巧

普通的操作无论是fetchall()还是fetchone()都是先将数据载入到本地再进行计算,大量的数据会导致内存资源消耗光。解决办法是使用SSCurosr光标来处理。

然而,在python3下,MySQLdb模块不再提供支持,此时可以使用另一个模块PyMySQL,它支持python2和python3。

2. PyMySQL

PyMySQL是一个纯Python写的MySQL客户端,它的目标是替代MySQLdb,可以在CPython、PyPy、IronPython和Jython环境下运行。PyMySQL在MIT许可下发布。

PyMySQL的性能和MySQLdb几乎相当,如果对性能要求
不是特别的强,使用PyMySQL将更加方便。

PyMySQL的使用方法和MySQLdb几乎一样。

安装

pip install pymysql

实例

#!/usr/bin/env python# -*- coding: utf-8 -*-import pymysql

config = {

    ‘host’: ‘127.0.0.1’,

    ‘port’: 3306,

    ‘user’: ‘root’,

    ‘passwd’: ‘root’,

    ‘charset’:’utf8mb4′,

    ‘cursorclass’:pymysql.cursors.DictCursor

    }

conn = pymysql.connect(**config)

conn.autocommit(1)

cursor = conn.cursor()

try:

    # 创建数据库

    DB_NAME = ‘test’

    cursor.execute(‘DROP DATABASE IF EXISTS %s’ %DB_NAME)

    cursor.execute(‘CREATE DATABASE IF NOT EXISTS %s’ %DB_NAME)

    conn.select_db(DB_NAME)

    #创建表

    TABLE_NAME = ‘user’

    cursor.execute(‘CREATE TABLE %s(id int primary key,name varchar(30))’ %TABLE_NAME)

    # 批量插入纪录

    values = []

    for i in range(20):

        values.append((i,’kk’+str(i)))

    cursor.executemany(‘INSERT INTO user values(%s,%s)’,values)

    # 查询数据条目

    count = cursor.execute(‘SELECT * FROM %s’ %TABLE_NAME)

    print ‘total records:’, cursor.rowcount

    # 获取表名信息

    desc = cursor.description

    print “%s %3s” % (desc[0][0], desc[1][0])

    cursor.scroll(10,mode=’absolute’)

    results = cursor.fetchall()

    for result in results:

        print result

except:

    import traceback

    traceback.print_exc()

    # 发生错误时会滚

    conn.rollback()finally:

    # 关闭游标连接

    cursor.close()

    # 关闭数据库连接

    conn.close()

输出结果:

total records: 20

id name

{u’id’: 10, u’name’: u’kk10′}

{u’id’: 11, u’name’: u’kk11′}

{u’id’: 12, u’name’: u’kk12′}

{u’id’: 13, u’name’: u’kk13′}

{u’id’: 14, u’name’: u’kk14′}

{u’id’: 15, u’name’: u’kk15′}

{u’id’: 16, u’name’: u’kk16′}

{u’id’: 17, u’name’: u’kk17′}

{u’id’: 18, u’name’: u’kk18′}

{u’id’: 19, u’name’: u’kk19′}

Java的几种设计模式

java的设计模式大体上分为三大类:

  • 创建型模式(5种):工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式。
  • 结构型模式(7种):适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组合模式,享元模式。
  • 行为型模式(11种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

设计模式遵循的原则有6个:

1、开闭原则(Open Close Principle)

  对扩展开放,对修改关闭

2、里氏代换原则(Liskov Substitution Principle)

  只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。

3、依赖倒转原则(Dependence Inversion Principle)

  这个是开闭原则的基础,对接口编程,依赖于抽象而不依赖于具体。

4、接口隔离原则(Interface Segregation Principle)

  使用多个隔离的借口来降低耦合度。

5、迪米特法则(最少知道原则)(Demeter Principle)

  一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。

6、合成复用原则(Composite Reuse Principle)

  原则是尽量使用合成/聚合的方式,而不是使用继承。继承实际上破坏了类的封装性,超类的方法可能会被子类修改。

1. 工厂模式(Factory Method)

  常用的工厂模式是静态工厂,利用static方法,作为一种类似于常见的工具类Utils等辅助效果,一般情况下工厂类不需要实例化。

interface food{}

class A implements food{}

class B implements food{}

class C implements food{}

public class StaticFactory {

    private StaticFactory(){}

    public static food getA(){  return new A(); }

    public static food getB(){  return new B(); }

    public static food getC(){  return new C(); }

}

class Client{

    //客户端代码只需要将相应的参数传入即可得到对象

    //用户不需要了解工厂类内部的逻辑。

    public void get(String name){

        food x = null ;

        if ( name.equals(“A”)) {

            x = StaticFactory.getA();

        }else if ( name.equals(“B”)){

            x = StaticFactory.getB();

        }else {

            x = StaticFactory.getC();

        }

    }

}

2. 抽象工厂模式(Abstract Factory)

  一个基础接口定义了功能,每个实现接口的子类就是产品,然后定义一个工厂接口,实现了工厂接口的就是工厂,这时候,接口编程的优点就出现了,我们可以新增产品类(只需要实现产品接口),只需要同时新增一个工厂类,客户端就可以轻松调用新产品的代码。

  抽象工厂的灵活性就体现在这里,无需改动原有的代码,毕竟对于客户端来说,静态工厂模式在不改动StaticFactory类的代码时无法新增产品,如果采用了抽象工厂模式,就可以轻松的新增拓展类。

  实例代码:

interface food{}

class A implements food{}

class B implements food{}

interface produce{ food get();}

class FactoryForA implements produce{

    @Override

    public food get() {

        return new A();

    }

}

class FactoryForB implements produce{

    @Override

    public food get() {

        return new B();

    }

}

public class AbstractFactory {

    public void ClientCode(String name){

        food x= new FactoryForA().get();

        x = new FactoryForB().get();

    }

}

3. 单例模式(Singleton)

   在内部创建一个实例,构造器全部设置为private,所有方法均在该实例上改动,在创建上要注意类的实例化只能执行一次,可以采用许多种方法来实现,如Synchronized关键字,或者利用内部类等机制来实现。

public class Singleton {

    private Singleton(){}

    private static class SingletonBuild{

        private static Singleton value = new Singleton();

    }

    public Singleton getInstance(){  return  SingletonBuild.value ;}

}

4.建造者模式(Builder)

  在了解之前,先假设有一个问题,我们需要创建一个学生对象,属性有name,number,class,sex,age,school等属性,如果每一个属性都可以为空,也就是说我们可以只用一个name,也可以用一个school,name,或者一个class,number,或者其他任意的赋值来创建一个学生对象,这时该怎么构造?

  难道我们写6个1个输入的构造函数,15个2个输入的构造函数…….吗?这个时候就需要用到Builder模式了。给个例子,大家肯定一看就懂:

public class Builder {

    static class Student{

        String name = null ;

        int number = -1 ;

        String sex = null ;

        int age = -1 ;

        String school = null ;

     //构建器,利用构建器作为参数来构建Student对象

        static class StudentBuilder{

            String name = null ;

            int number = -1 ;

            String sex = null ;

            int age = -1 ;

            String school = null ;

            public StudentBuilder setName(String name) {

                this.name = name;

                return  this ;

            }

            public StudentBuilder setNumber(int number) {

                this.number = number;

                return  this ;

            }

            public StudentBuilder setSex(String sex) {

                this.sex = sex;

                return  this ;

            }

            public StudentBuilder setAge(int age) {

                this.age = age;

                return  this ;

            }

            public StudentBuilder setSchool(String school) {

                this.school = school;

                return  this ;

            }

            public Student build() {

                return new Student(this);

            }

        }

        public Student(StudentBuilder builder){

            this.age = builder.age;

            this.name = builder.name;

            this.number = builder.number;

            this.school = builder.school ;

            this.sex = builder.sex ;

        }

    }

    public static void main( String[] args ){

        Student a = new Student.StudentBuilder().setAge(13).setName(“LiHua”).build();

        Student b = new Student.StudentBuilder().setSchool(“sc”).setSex(“Male”).setName(“ZhangSan”).build();

    }

}

5. 原型模式(Protype)

原型模式就是讲一个对象作为原型,使用clone()方法来创建新的实例。

public class Prototype implements Cloneable{

    private String name;

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    @Override

    protected Object clone()   {

        try {

            return super.clone();

        } catch (CloneNotSupportedException e) {

            e.printStackTrace();

        }finally {

            return null;

        }

    }

    public static void main ( String[] args){

        Prototype pro = new Prototype();

        Prototype pro1 = (Prototype)pro.clone();

    }

}

此处使用的是浅拷贝,关于深浅拷贝,大家可以另行查找相关资料。

6.适配器模式(Adapter)

适配器模式的作用就是在原来的类上提供新功能。主要可分为3种:

  • 类适配:创建新类,继承源类,并实现新接口,例如 

class  adapter extends oldClass  implements newFunc{}

  • 对象适配:创建新类持源类的实例,并实现新接口,例如 

class adapter implements newFunc { private oldClass oldInstance ;}

  • 接口适配:创建新的抽象类实现旧接口方法。例如 

abstract class adapter implements oldClassFunc { void newFunc();}

7.装饰模式(Decorator)

 给一类对象增加新的功能,装饰方法与具体的内部逻辑无关。例如:

interface Source{ void method();}

public class Decorator implements Source{

    private Source source ;

    public void decotate1(){

        System.out.println(“decorate”);

    }

    @Override

    public void method() {

        decotate1();

        source.method();

    }

}

8.代理模式(Proxy)

客户端通过代理类访问,代理类实现具体的实现细节,客户只需要使用代理类即可实现操作。

这种模式可以对旧功能进行代理,用一个代理类调用原有的方法,且对产生的结果进行控制。

interface Source{ void method();}

class OldClass implements Source{

    @Override

    public void method() {

    }

}

class Proxy implements Source{

    private Source source = new OldClass();

    void doSomething(){}

    @Override

    public void method() {

        new Class1().Func1();

        source.method();

        new Class2().Func2();

        doSomething();

    }

}

9.外观模式(Facade)

为子系统中的一组接口提供一个一致的界面,定义一个高层接口,这个接口使得这一子系统更加容易使用。这句话是百度百科的解释,有点难懂,但是没事,看下面的例子,我们在启动停止所有子系统的时候,为它们设计一个外观类,这样就可以实现统一的接口,这样即使有新增的子系统subSystem4,也可以在不修改客户端代码的情况下轻松完成。

public class Facade {

    private subSystem1 subSystem1 = new subSystem1();

    private subSystem2 subSystem2 = new subSystem2();

    private subSystem3 subSystem3 = new subSystem3();

    public void startSystem(){

        subSystem1.start();

        subSystem2.start();

        subSystem3.start();

    }

    public void stopSystem(){

        subSystem1.stop();

        subSystem2.stop();

        subSystem3.stop();

    }

}

10.桥接模式(Bridge)

这里引用下http://www.runoob.com/design-pattern/bridge-pattern.html的例子。Circle类将DrwaApi与Shape类进行了桥接,代码:

interface DrawAPI {

    public void drawCircle(int radius, int x, int y);

}

class RedCircle implements DrawAPI {

    @Override

    public void drawCircle(int radius, int x, int y) {

        System.out.println(“Drawing Circle[ color: red, radius: “

                + radius +”, x: ” +x+”, “+ y +”]”);

    }

}

class GreenCircle implements DrawAPI {

    @Override

    public void drawCircle(int radius, int x, int y) {

        System.out.println(“Drawing Circle[ color: green, radius: “

                + radius +”, x: ” +x+”, “+ y +”]”);

    }

}

abstract class Shape {

    protected DrawAPI drawAPI;

    protected Shape(DrawAPI drawAPI){

        this.drawAPI = drawAPI;

    }

    public abstract void draw();

}

class Circle extends Shape {

    private int x, y, radius;

    public Circle(int x, int y, int radius, DrawAPI drawAPI) {

        super(drawAPI);

        this.x = x;

        this.y = y;

        this.radius = radius;

    }

    public void draw() {

        drawAPI.drawCircle(radius,x,y);

    }

}

//客户端使用代码

Shape redCircle = new Circle(100,100, 10, new RedCircle());

Shape greenCircle = new Circle(100,100, 10, new GreenCircle());

redCircle.draw();

greenCircle.draw();

11.组合模式(Composite)

 组合模式是为了表示那些层次结构,同时部分和整体也可能是一样的结构,常见的如文件夹或者树。举例:

abstract class component{}

class File extends  component{ String filename;}

class Folder extends  component{

    component[] files ;  //既可以放文件File类,也可以放文件夹Folder类。Folder类下又有子文件或子文件夹。

    String foldername ;

    public Folder(component[] source){ files = source ;}

    public void scan(){

        for ( component f:files){

            if ( f instanceof File){

                System.out.println(“File “+((File) f).filename);

            }else if(f instanceof Folder){

                Folder e = (Folder)f ;

                System.out.println(“Folder “+e.foldername);

                e.scan();

            }

        }

    }

}

12.享元模式(Flyweight)

使用共享对象的方法,用来尽可能减少内存使用量以及分享资讯。通常使用工厂类辅助,例子中使用一个HashMap类进行辅助判断,数据池中是否已经有了目标实例,如果有,则直接返回,不需要多次创建重复实例。

abstract class flywei{ }

public class Flyweight extends flywei{

    Object obj ;

    public Flyweight(Object obj){

        this.obj = obj;

    }

}

class  FlyweightFactory{

    private HashMap<Object,Flyweight> data;

    public FlyweightFactory(){ data = new HashMap<>();}

    public Flyweight getFlyweight(Object object){

        if ( data.containsKey(object)){

            return data.get(object);

        }else {

            Flyweight flyweight = new Flyweight(object);

            data.put(object,flyweight);

            return flyweight;

        }

    }

}

retrying failed action with response code: 403 解决方法

原文:https://www.toocruel.net/logstash-outputs-elasticsearch-retrying-individual-bulk-actions-that-failed-or-were-rejected-by-the-previous-bulk-request-count-1/
在用logstash收集mysql数据到elasticsearch中时,运行一段时间后就出错:

[2018-09-27T10:56:46,330][INFO ][logstash.outputs.elasticsearch] retrying failed action with response code: 403 ({“type”=>”cluster_block_exception”, “reason”=>”blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];”})

[2018-09-27T10:56:46,330][INFO ][logstash.outputs.elasticsearch] Retrying individual bulk actions that failed or were rejected by the previous bulk request. {:count=>1}

  • 1
  • 2

日志原文:

[2018-09-11T20:07:53,152][INFO ][logstash.outputs.elasticsearch] Retrying individual bulk actions that failed or were rejected by the previous bulk request. {:count=>1}

[2018-09-11T20:07:53,152][INFO ][logstash.outputs.elasticsearch] retrying failed action with response code: 403 ({“type”=>”cluster_block_exception”, “reason”=>”blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];”})

[2018-09-11T20:07:53,152][INFO ][logstash.outputs.elasticsearch] Retrying individual bulk actions that failed or were rejected by the previous bulk request. {:count=>1}

[2018-09-11T20:07:53,160][INFO ][logstash.outputs.elasticsearch] retrying failed action with response code: 403 ({“type”=>”cluster_block_exception”, “reason”=>”blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];”})

[2018-09-11T20:07:53,160][INFO ][logstash.outputs.elasticsearch] Retrying individual bulk actions that failed or were rejected by the previous bulk request. {:count=>1}

[2018-09-11T20:07:56,967][INFO ][logstash.outputs.elasticsearch] retrying failed action with response code: 403 ({“type”=>”cluster_block_exception”, “reason”=>”blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];”})

[2018-09-11T20:07:56,967][INFO ][logstash.outputs.elasticsearch] Retrying individual bulk actions that failed or were rejected by the previous bulk request. {:count=>1}

[2018-09-11T20:08:00,233][INFO ][logstash.inputs.jdbc     ] (0.000699s) select * from news_cast  where createTime >=1536667203783.0 and opCode=8 and createTime>1504770772000 limit 10000

[2018-09-11T20:08:01,459][INFO ][logstash.outputs.elasticsearch] retrying failed action with response code: 403 ({“type”=>”cluster_block_exception”, “reason”=>”blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];”})

[2018-09-11T20:08:01,459][INFO ][logstash.outputs.elasticsearch] retrying failed action with response code: 403 ({“type”=>”cluster_block_exception”, “reason”=>”blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];”})

[2018-09-11T20:08:01,459][INFO ][logstash.outputs.elasticsearch] Retrying individual bulk actions that failed or were rejected by the previous bulk request. {:count=>2}

[2018-09-11T20:08:05,160][INFO ][logstash.outputs.elasticsearch] retrying failed action with response code: 403 ({“type”=>”cluster_block_exception”, “reason”=>”blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];”})

[2018-09-11T20:08:05,160][INFO ][logstash.outputs.elasticsearch] Retrying individual bulk actions that failed or were rejected by the previous bulk request. {:count=>1}

[2018-09-11T20:08:05,160][INFO ][logstash.outputs.elasticsearch] retrying failed action with response code: 403 ({“type”=>”cluster_block_exception”, “reason”=>”blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];”})

[2018-09-11T20:08:05,160][INFO ][logstash.outputs.elasticsearch] Retrying individual bulk actions that failed or were rejected by the previous bulk request. {:count=>1}

[2018-09-11T20:08:55,273][INFO ][logstash.outputs.elasticsearch] retrying failed action with response code: 403 ({“type”=>”cluster_block_exception”, “reason”=>”blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];”})

[2018-09-11T20:08:55,273][INFO ][logstash.outputs.elasticsearch] Retrying individual bulk actions that failed or were rejected by the previous bulk request. {:count=>1}

[2018-09-11T20:08:57,155][INFO ][logstash.outputs.elasticsearch] retrying failed action with response code: 403 ({“type”=>”cluster_block_exception”, “reason”=>”blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];”})

[2018-09-11T20:08:57,155][INFO ][logstash.outputs.elasticsearch] Retrying individual bulk actions that failed or were rejected by the previous bulk request. {:count=>1}

[2018-09-11T20:08:57,156][INFO ][logstash.outputs.elasticsearch] retrying failed action with response code: 403 ({“type”=>”cluster_block_exception”, “reason”=>”blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];”})

[2018-09-11T20:08:57,156][INFO ][logstash.outputs.elasticsearch] Retrying individual bulk actions that failed or were rejected by the previous bulk request. {:count=>1}

[2018-09-11T20:08:57,162][INFO ][logstash.outputs.elasticsearch] retrying failed action with response code: 403 ({“type”=>”cluster_block_exception”, “reason”=>”blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];”})

[2018-09-11T20:08:57,162][INFO ][logstash.outputs.elasticsearch] Retrying individual bulk actions that failed or were rejected by the previous bulk request. {:count=>1}

[2018-09-11T20:09:00,267][INFO ][logstash.inputs.jdbc     ] (0.000573s) select * from news_cast  where createTime >=1536667680170.0 and opCode=8 and createTime>1504770772000 limit 10000

[2018-09-11T20:09:00,969][INFO ][logstash.outputs.elasticsearch] retrying failed action with response code: 403 ({“type”=>”cluster_block_exception”, “reason”=>”blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];”})

按照 Eleastisearch 官方文档给的解决办法是

An example of resetting the read-only index block on the twitter index:

PUT /twitter/_settings
{
“index.blocks.read_only_allow_delete”: null
}

官方的链接是 : 点击这里查看

按照官方给的这个解决思路,在linux上执行:

curl -XPUT -H ‘Content-Type: application/json’ http://106.14.46.249:9200/_all/_settings -d ‘{“index.blocks.read_only_allow_delete”: null}’

  • 1

其中 _all 这个可以更改为自己在创建 Eleastisearch 索引的时候的name,用来修改单个索引只读状态,当然用 _all 也可以, _all 是修改了所有的索引只读状态

PUT /_all/_settings
{
“index.blocks.read_only_allow_delete”: null
}