S3 Select for Java 使用记录
背景
后台基本使用 Amazon 的全家桶(EC2、DynamoDB、S3、Step Fuction 等等)构建。现在需要根据访问者的 IP 确定访问者的国家或地区。
已知:
访问者 IP
一个 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。
参考
S3 Select for Java 使用记录的更多相关文章
- Java 日志记录规则
Java 日志记录规则 规则一:日志是面向读者的 我们不应该让无价值的信息使日志文件变得乱糟糟,比如说完整打印所有的实体字段. 通常,实体名字和其逻辑关键字足以识别在表格中的一条记录了. 规则二:匹配 ...
- 补充Java面试记录
补充Java面试记录 背景:这两天面试遇到的部分问题都分散在了前面两篇文摘中,这里再做一些其他的记录,以备不时之需! 一.谈谈你对SpringBoot的理解? SpringBoot简介:SpringB ...
- Java问题记录——循环里的二次判断与状态更新
Java问题记录——循环里的二次判断与状态更新 摘要:本文主要记录了在循环操作时可能出现的问题. 问题重现 在使用循环结构时,如果使用了定时任务,或者代码会多次调用循环结构,可能会导致有些对象会被循环 ...
- Java问题记录——OutOfMemoryError
Java问题记录——OutOfMemoryError 摘要:本文主要分析了OutOfMemoryError的产生原因. 没有分页导致占用大量内存 查看进程 使用 jps 命令查看当前运行的Java进程 ...
- Java问题记录——IllegalMonitorStateException
Java问题记录——IllegalMonitorStateException 摘要:本文主要分析了IllegalMonitorStateException的产生原因. 部分内容来自以下博客: http ...
- SLF4J (The Simple Logging Facade for Java)使用记录
SLF4J (The Simple Logging Facade for Java)使用记录 官网 http://www.slf4j.org/ 参考资料 官方文档 什么是 SLF4J? 官网: The ...
- 【Java】记录一次代码优化
前不久的项目时间紧张,为了尽快完成原型开发,写了一段效率相当低的代码. 最近几天闲下来,主动把之前的代码优化了一下:) 标签:Java.Mybatis.MySQL 概况:本地系统从另外一个系统得到 ...
- 普华永道高级JAVA面试记录
最近在考虑换个工作 原因?咱能不逗吗? 一面感觉发挥不错 二面之后累觉不爱 基本上浪费了半天的工资(好多钱啊~~~) PWD上海地址在浦东软件园 工作环境说实话没我现在工作的环境好,不过里面的人 ...
- Java学习笔记(十九)——Java 日志记录 AND log4j
[前面的话] 学习的进度应该稍微在快一点. Java日志到了必须学习怎么使用的时候了,因为在项目中要进行使用.基础性文章,选择性阅读. [结构] java日志对调试,记录运行,问题定位都起到了很重要的 ...
随机推荐
- scrapy实战3利用fiddler对手机app进行抓包爬虫图片下载(重写ImagesPipeline):
关于fiddler的使用方法参考(http://jingyan.baidu.com/article/03b2f78c7b6bb05ea237aed2.html) 本案例爬取斗鱼 app 先利用fidd ...
- 20190101.DDD笔记
建立领域模型步骤 根据提供的信息完善主要业务场景和业务流程: 根据业务流程识别领域事件并按照时序排列: 针对领域事件进行命令识别: 针对领域事件和命令进行聚合和子域的初步识别: 在识别的subdoma ...
- 洛谷P1396 营救 题解
题目:https://www.luogu.org/problemnew/show/P1396 分析: 这其实一看就是一个最短路的近似模板的题目,但我们要注意到两个区之间可能会有多条道路,所以说我们只需 ...
- 简单的量子算法(二):Simon's Algorithm
前情回顾: 简单的量子算法(一):Hadamard 变换.Parity Problem 好的,现在开始正版的故事,Simon's Algorithm 问题: 有一个secret string,是n位的 ...
- 个人永久性免费-Excel催化剂功能第96波-地图数据挖宝之全国天气查询(区域最细可到区县,最长预报4天)
天气预报的信息,是很普通的大家习以为常的信息,但如果不进行采集,在日常数据分析过程中,就少了非常重要的一个分析维度,如果人手采集整理,工作量巨大.此篇给广大数据分析工作者再次减负,只需简单一键,即可批 ...
- 利用百度AI OCR图片识别,Java实现PDF中的图片转换成文字
序言:我们在读一些PDF版书籍的时候,如果PDF中不是图片,做起读书笔记的还好:如果PDF中的是图片的话,根本无法编辑,做起笔记来,还是很痛苦的.我是遇到过了.我们搞技术的,当然得自己学着解决现在的痛 ...
- python模块导入-软件开发目录规范-01
模块 模块的基本概念 模块: # 一系列功能的结合体 模块的三种来源 """ 模块的三种来源 1.python解释器内置的模块(os.sys....) 2.第三方的别人写 ...
- python UUID
UUID介绍 UUID是128位的全局唯一标识符,通常由32字节的字符串表示.它可以保证时间和空间的唯一性,也称为GUID,全称为:UUID ―― Universally Unique IDentif ...
- Linux小火车和流星雨
一.流星雨 [root@localhost ~]# wget https://jaist.dl.sourceforge.net/project/cmatrix/cmatrix/1.2a/cmatrix ...
- 说说Java线程间通信
序言 正文 [一] Java线程间如何通信? 线程间通信的目标是使线程间能够互相发送信号,包括如下几种方式: 1.通过共享对象通信 线程间发送信号的一个简单方式是在共享对象的变量里设置信号值:线程A在 ...