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日志对调试,记录运行,问题定位都起到了很重要的 ... 
随机推荐
- HDU 5791:Two(DP)
			http://acm.hdu.edu.cn/showproblem.php?pid=5791 Two Problem Description Alice gets two sequences A ... 
- mysql 免安装版本 与问题记录
			将文件解压到D盘, 创建 my.ini 配置文件, ------------------复制进去--------------------- [client] port=3306 default-cha ... 
- 2017《java技术预备作业》
			2017<java技术预备作业> 1.阅读邹欣老师的博客,谈谈你期望的师生关系是什么样的? 亦师亦友,很多人这样说,确实,倘若师生之间如果中间有些隔阂最终吃亏的始终是学生.我认为师生之间应 ... 
- 《Predict Anchor Links across Social Networks via an Embedding Approach》阅读笔记
			基本信息 文献:Predict Anchor Links across Social Networks via an Embedding Approach 时间:2016 期刊:IJCAI 引言 预测 ... 
- Bzoj 2839 集合计数 题解
			2839: 集合计数 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 495 Solved: 271[Submit][Status][Discuss] ... 
- 算法导论--最小生成树(Kruskal和Prim算法)
			转载出处:勿在浮沙筑高台http://blog.csdn.net/luoshixian099/article/details/51908175 关于图的几个概念定义: 连通图:在无向图中,若任意两个顶 ... 
- 【CYH-02】NOIp考砸后虐题赛:成绩:题解
			这道题挺送水了吧... 两种做法. 其实空间都不需要那么大,我来提交界面一看一堆MLE的,于是还是良心的放开了时限. 这么简单,就不做解释了. 下面放出几种代码. 代码: 两个数组: #include ... 
- 【转】Spring事务详解
			1.事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交,那在没有Spring帮我们管理事务 ... 
- pyqt 主程序运行中处理其他事件(多线程的一种代替方式)
			一.实验环境 1.Windows7x64_SP1 2.Anaconda2.5.0 + python2.7(anaconda集成,不需单独安装) 3.pyinstaller3.0 4.通过Anacond ... 
- Vue的基本使用(二)
			1.数据的双向绑定 <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ... 
