背景

后台基本使用 Amazon 的全家桶(EC2、DynamoDB、S3、Step Fuction 等等)构建。现在需要根据访问者的 IP 确定访问者的国家或地区。

已知:

  1. 访问者 IP

  2. 一个 ipdata.csv 文件,已放置在 S3 的桶 ow-public-us 中,格式如下

    ip_from ip_to country_code country_name
    0 16777215 - -
    16777216 16777471 AU Australia
    16777472 16778239 CN China

流程

1. 引入 S3 Select

compile "com.amazonaws:aws-java-sdk-s3:1.11.379"

2. 构建 AmazonS3 对象

public AmazonS3 createAmazonS3(){
final AwsSupport awsSupport = new AwsSupport();
ClientConfiguration clientConfiguration = new ClientConfiguration();
clientConfiguration.setSocketTimeout((int) TimeUnit.SECONDS.toMillis(70));
AmazonS3ClientBuilder builder = AmazonS3ClientBuilder.standard()
.withCredentials(awsSupport.getCredentials())
.withClientConfiguration(
clientConfiguration);
// ). region
final Region region = awsSupport.getCurrentRegion();
if (region != null) {
builder.withRegion(region.getName());
}
return builder.build();
}

3. 构建 SelectObjectContentRequest 对象

本文中输入的为 CSV 无压缩数据,输出为 Json 类型数据。

public static SelectObjectContentRequest createBaseCSVRequest(String bucket,
String key,
String query) {
SelectObjectContentRequest request = new SelectObjectContentRequest();
request.setBucketName(bucket);
request.setKey(key);
request.setExpression(query);
request.setExpressionType(ExpressionType.SQL); InputSerialization inputSerialization = new InputSerialization();
inputSerialization.setCsv(new CSVInput());
inputSerialization.setCompressionType(CompressionType.NONE);
request.setInputSerialization(inputSerialization); OutputSerialization outputSerialization = new OutputSerialization();
outputSerialization.setJson(new JSONOutput());
request.setOutputSerialization(outputSerialization);
return request;
}

4. 转化 IP 为 IP LONG

将 IP 字符串 转为 long 型数值,方便进行 IP 国家地区定位。

public static long ip2Long(String ipAddress) {
if (Strings.isNullOrEmpty(ipAddress)) {
return 0L;
}
long result = 0;
String[] ipAddressInArray = ipAddress.split("\\."); for (int i = 3; i >= 0; i--) {
long ip = Long.parseLong(ipAddressInArray[3 - i]);
// left shifting 24,16,8,0 and bitwise OR
// 1. 192 << 24
// 1. 168 << 16
// 1. 1 << 8
// 1. 2 << 0
result |= ip << (i * 8);
}
return result;
}

5. 请求并获取国家地区信息

// _1 代表第一列 ip_from
// _2 代表第二列 ip_to
// _3 代表第三列 country_code
// 注意: SQL 中的变量需要用单引号括起来
SelectObjectContentResult selectObjectContentResult =
createAmazonS3().selectObjectContent(createBaseCSVRequest("ow-public-us",
"ipdata.csv",
"SELECT s.\'country_code\' FROM S3Object s WHERE s._1<=\'" +
ipLong +
"\' AND s._2>=\'" +
ipLong + "\' LIMIT 1"));
selectObjectContentResult.getPayload()
.getRecordsInputStream(new SelectObjectContentEventVisitor() {
@Override
public void visit(SelectObjectContentEvent.RecordsEvent event) {
try {
String content =
new String(event.getPayload().array(), "utf-8");
LOGGER.debug("Country is --> {}", content);
JsonObject object = Json.fromJson(content, JsonObject.class);
String country = object.get("_3").getAsString();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
});

预警

在编辑 S3 Select 的 SQL 语句时,使用下列形式是不支持的:

// 出错:AmazonS3Exception: The column index at line 1, column 8 is invalid. Please check the service documentation and try again. (Service: Amazon S3; Status Code: 400; Error Code: InvalidColumnIndex;
String sql = "SELECT s.\"country_code\" FROM S3Object s WHERE s._1<=\'" + ipLong +"\' AND s._2>=\'" + ipLong + "\' LIMIT 1"; // 出错:AmazonS3Exception: Invalid Path component, expecting either an IDENTIFIER or STAR, got: LITERAL,at line 1, column 10. (Service: Amazon S3; Status Code: 400; Error Code: ParseInvalidPathComponent;
String sql = "SELECT s.\'country_code\' FROM S3Object s WHERE s._1<=\'" + ipLong +"\' AND s._2>=\'" + ipLong + "\' LIMIT 1"; // 出错:AmazonS3Exception: The column index at line 1, column 8 is invalid. Please check the service documentation and try again. (Service: Amazon S3; Status Code: 400; Error Code: InvalidColumnIndex;
String sql = "SELECT s.country_code FROM S3Object s WHERE s._1<=\'" + ipLong +"\' AND s._2>=\'" + ipLong + "\' LIMIT 1";

但是第一种写法在 Python 库 boto3 中是支持的,可以参见 参考2

参考

  1. 使用 适用于 Java 的开发工具包 从对象中选择内容 - Amazon
  2. S3 Select — new revolution “at rest” - Medium

S3 Select for Java 使用记录的更多相关文章

  1. Java 日志记录规则

    Java 日志记录规则 规则一:日志是面向读者的 我们不应该让无价值的信息使日志文件变得乱糟糟,比如说完整打印所有的实体字段. 通常,实体名字和其逻辑关键字足以识别在表格中的一条记录了. 规则二:匹配 ...

  2. 补充Java面试记录

    补充Java面试记录 背景:这两天面试遇到的部分问题都分散在了前面两篇文摘中,这里再做一些其他的记录,以备不时之需! 一.谈谈你对SpringBoot的理解? SpringBoot简介:SpringB ...

  3. Java问题记录——循环里的二次判断与状态更新

    Java问题记录——循环里的二次判断与状态更新 摘要:本文主要记录了在循环操作时可能出现的问题. 问题重现 在使用循环结构时,如果使用了定时任务,或者代码会多次调用循环结构,可能会导致有些对象会被循环 ...

  4. Java问题记录——OutOfMemoryError

    Java问题记录——OutOfMemoryError 摘要:本文主要分析了OutOfMemoryError的产生原因. 没有分页导致占用大量内存 查看进程 使用 jps 命令查看当前运行的Java进程 ...

  5. Java问题记录——IllegalMonitorStateException

    Java问题记录——IllegalMonitorStateException 摘要:本文主要分析了IllegalMonitorStateException的产生原因. 部分内容来自以下博客: http ...

  6. SLF4J (The Simple Logging Facade for Java)使用记录

    SLF4J (The Simple Logging Facade for Java)使用记录 官网 http://www.slf4j.org/ 参考资料 官方文档 什么是 SLF4J? 官网: The ...

  7. 【Java】记录一次代码优化

    前不久的项目时间紧张,为了尽快完成原型开发,写了一段效率相当低的代码. 最近几天闲下来,主动把之前的代码优化了一下:)   标签:Java.Mybatis.MySQL 概况:本地系统从另外一个系统得到 ...

  8. 普华永道高级JAVA面试记录

    最近在考虑换个工作 原因?咱能不逗吗? 一面感觉发挥不错  二面之后累觉不爱  基本上浪费了半天的工资(好多钱啊~~~) PWD上海地址在浦东软件园  工作环境说实话没我现在工作的环境好,不过里面的人 ...

  9. Java学习笔记(十九)——Java 日志记录 AND log4j

    [前面的话] 学习的进度应该稍微在快一点. Java日志到了必须学习怎么使用的时候了,因为在项目中要进行使用.基础性文章,选择性阅读. [结构] java日志对调试,记录运行,问题定位都起到了很重要的 ...

随机推荐

  1. SPOJ MINSUB - Largest Submatrix(二分+单调栈)

    http://www.spoj.com/problems/MINSUB/en/ 题意:给出一个n*m的矩阵M,和一个面积k,要使得M的子矩阵M'的最小元素最大并且面积大于等于k,问子矩阵M'的最小元素 ...

  2. Codeforces 776C:Molly's Chemicals(思维)

    http://codeforces.com/problemset/problem/776/C 题意:给出一个有n个数的序列,还有一个k,问在这个序列中有多少个子序列使得sum[l, r] = k^0, ...

  3. c语言学习书籍推荐《C语言学习路线图•C语言必须知道的300个问题》下载

    下载地址:点我 <C语言学习路线图•C语言必须知道的300个问题>以基础知识为框架,介绍了c语言各部分知识所对应的常见开发疑难问题,并作了透彻地解析.<C语言学习路线图•C语言必须知 ...

  4. 用Supervisor实现进程守护,在异常退出时自动重启

    程序启动后,有些是以daemon的形式运行,但在意外退出后,如果不能及时重新启动,会有比较严重的影响. 比如Zimg在图片处理中由于某些图片处理失败,会导致zimg进程挂掉,影响正常的服务提供,并且只 ...

  5. py+selenium 自动判断页面是否报错并显示在自动化测试报告【原创】

    有需求就会去研究解决的路子. 现在需求就是,测试报告报错信息一堆,但却无法肉眼看出是什么问题,你只能知道定位不到元素或是超时,但你却不知道其实进入页面就报错了或是提交表单就报错了!也就是看到报错,需要 ...

  6. JavaScript剩余操作符Rest Operator

    本文适合JavaScript初学者阅读 剩余操作符 之前这篇文章JavaScript展开操作符(Spread operator)介绍讲解过展开操作符.剩余操作符和展开操作符的表示方式一样,都是三个点 ...

  7. app同包同签名不能安装问题

    今天博主与团队之间出现一个很郁闷的问题: 那就是我们开发的一个app,在升级推送版本的时候突然出现,相同的包名.相同的签名.在安装的时候出现,安装签名不一致(安装失败)的提示. 让我们很是困扰.后来发 ...

  8. php重复开启session

    虽然不知道 自己怎么就在一个后台系统页面中重复开启了session, 但是为了避免重复开始session的问题,可以使用: if (!session_id()) session_start(); 以上 ...

  9. DAX 第六篇:统计函数

    统计函数用于创建聚合,对数据进行统计分析.在使用统计函数时,必须考虑到数据模型,表之间关系,数据重复等因素,一般都会搭配过滤函数实现数据的提取和分析. 统计量一般是:均值.求和.计数.最大值.最小值. ...

  10. Linux卸载MySql——ubuntu版

    卸载mysql 1)删除mysql的数据文件 sudo rm /var/lib/mysql/ -R 2)删除mqsql的配置文件 sudo rm /etc/mysql/ -R 3)自动卸载mysql的 ...