Phoenix 指南-01
Phoenix 指南-01
create 'jinshan' ,'info','info1'
put 'jinshan','1001','info:createtime',Bytes.toBytes(1602237645881)
put 'jinshan','1001','info1:age',Bytes.toBytes(16)
create view "jinshan" (id varchar primary key,"info"."createtime" UNSIGNED_DATE,"info1"."age" UNSIGNED_LONG)column_encoded_bytes=0;
select * from "jinshan";
create table "t2_hbase" (id varchar primary key,"mycg"."age" UNSIGNED_INT,"mycg"."datestr" UNSIGNED_DATE,"mycg"."name" varchar)column_encoded_bytes=0;
select * from "t2_hbase";
create table user (
"session_id" varchar(100) not null primary key,
"f"."cookie_id" varchar(100),
"f"."visit_time" varchar(100),
"f"."user_id" varchar(100),
"f"."age" Integer,
"f"."sex" varchar(100),
"f"."visit_url" varchar(100),
"f"."visit_os" varchar(100),
"f"."browser_name" varchar(100),
"f"."visit_ip" varchar(100),
"f"."province" varchar(100),
"f"."city" varchar(100),
"f"."page_id" varchar(100),
"f"."goods_id" varchar(100),
"f"."shop_id" varchar(100)) column_encoded_bytes=0;
phoenix-psql -t USER localhost:2181 /data/leo_jie/user.csv
备注:因为我安装的是 CDH 版的 Phoenix,所以命令会和原文略有不同。这种方式导入数据的效率挺慢的,数据量大的话还是推荐使用之前提到的 bulkload CSV 文件的方式。500 万的测试数据大概三个 G,导入耗时 15 分钟左右。
create index USER_COOKIE_ID_INDEX on USER ("f"."cookie_id");
create local index USER_USER_ID_INDEX on USER ("f"."user_id");
drop index USER_USER_ID_INDEX on "USER";
create local index USER_USER_ID_INDEX on USER ("f"."user_id") async;
hbase org.apache.phoenix.mapreduce.index.IndexTool --data-table USER --index-table USER_USER_ID_INDEX --output-path USER_USER_ID_INDEX
${HBASE_HOME}/bin/hbase org.apache.phoenix.mapreduce.index.IndexTool
--schema MY_SCHEMA --data-table MY_TABLE --index-table ASYNC_IDX
--output-path ASYNC_IDX_HFILES
create index USER_COOKIE_ID_AGE_INDEX on USER ("f"."cookie_id") include("f"."age");
第三种方式是在查询的时候提示其使用索引。 在 select 和 column_name 之间加上/+ Index(<表名> <index 名>)/,通过这种方式强制使用索引。
select /*+ index(user,USER_COOKIE_ID_AGE_INDEX) */ "age" from user where "cookie_id"='b80da72c-c6e4-4c79-9fc5-08e7253f6596';
select /*+ index(user, USER_COOKIE_ID_AGE_INDEX) */"age","sex" from user where "cookie_id"='b80da72c-c6e4-4c79-9fc5-08e7253f6596';
select /*+ index(user USER_COOKIE_ID_AGE_INDEX) */"age", "sex" from user where "cookie_id"='b80da72c-c6e4-4c79-9fc5-08e7253f6596';
explain select /*+ index(user USER_COOKIE_ID_AGE_INDEX) */"age", "sex" from user where "cookie_id"='b80da72c-c6e4-4c79-9fc5-08e7253f6596';
1 alter index USER_PHONE_INDEX on person.USER rebuild;
2 alter index USER_PHONE_INDEX on person.USER rebuild async;
如果你的 Phoenix 表数据量很大,还是老老实实使用语句 2 来进行异步索引重建吧。异步索引重建之后,索引的状态被置为了 BUILDING,此时,还需要运行 IndexTool 命令来加载索引数据。
hbase org.apache.phoenix.mapreduce.index.IndexTool \
--schema PERSON --data-table USER --index-table USER_PHONE_INDEX \
--output-path USER_PHONE_INDEX
这里说起索引表的状态,不得不提一下索引表的生命周期。我们以异步的方式初次创建或者二次创建的索引表的状态是 BUILDING,即构建状态,此时索引表还不能正常使用,当我们运行完 IndexTool 这个索引表构建工具之后,索引表的状态被修改为 ACTIVE,意味激活状态。此时索引表就可以正常使用了,这里就涉及到了索引表的生命周期。有关生命周期更详细的介绍,还请移步至 Phoenix 的官方文档,或者参考此篇博客https://www.cnblogs.com/hbase-community/p/8879848.html
hbase-site.xml 配置
hbase-site.xml
1. index.builder.threads.max
创建索引时,使用的最大线程数。
默认值: 10。
2. index.builder.threads.keepalivetime
创建索引的创建线程池中线程的存活时间,单位:秒。
默认值: 60
3. index.writer.threads.max
写索引表数据的写线程池的最大线程数。
更新索引表可以用的最大线程数,也就是同时可以更新多少张索引表,数量最好和索引表的数量一致。
默认值: 10
4. index.writer.threads.keepalivetime
索引写线程池中,线程的存活时间,单位:秒。
默认值:60
5. hbase.htable.threads.max
每一张索引表可用于写的线程数。
默认值: 2,147,483,647
6. hbase.htable.threads.keepalivetime
索引表线程池中线程的存活时间,单位:秒。
默认值: 60
7. index.tablefactory.cache.size
允许缓存的索引表的数量。
增加此值,可以在写索引表时不用每次都去重复的创建htable,这个值越大,内存消耗越多。
默认值: 10
8. org.apache.phoenix.regionserver.index.handler.count
处理全局索引写请求时,可以使用的线程数。
默认值: 30
模拟测试数据的脚本
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
:Description: 模拟用户数据
:Owner: cw
:Create time: 2023年8月31日15:02:05
"""
import uuid
import time
import random
import struct
import socket
def generate_random_time():
a1 = (2018, 1, 1, 0, 0, 0, 0, 0, 0) # 设置开始日期时间元组(1976-01-01 00:00:00)
a2 = (2019, 12, 31, 23, 59, 59, 0, 0, 0) # 设置结束日期时间元组(1990-12-31 23:59:59)
start = time.mktime(a1) # 生成开始时间戳
end = time.mktime(a2) # 生成结束时间戳
# 随机生成10个日期字符串
t = random.randint(start, end) # 在开始和结束时间戳中随机取出一个
date_tuple = time.localtime(t) # 将时间戳生成时间元组
random_date = time.strftime("%Y-%m-%d %H:%M:%S", date_tuple) # 将时间元组转成格式化字符串
return random_date
def generate_random_user_id(length=9):
user_id = str(random.randint(1, 999999999))
if len(user_id) < length:
append_length = length - len(user_id)
user_id = '0' * append_length + user_id
return user_id
def random_str():
data = "1234567890zxcvbnmlkjhgfdsaqwertyuiop"
# 用时间来做随机播种
random.seed(time.time())
# 随机选取数据
sa = []
for i in range(20):
sa.append(random.choice(data))
salt = "gp_" + ''.join(sa)
return salt
def generate_random_url():
channels = [
"BTV2", "BTV3", "BTV4", "BTV5", "BTV6", "BTV7", "BTV8", "BTV9",
"BTVWorld", "CCTV12", "CCTV2", "CCTV3", "CCTV5", "CCTV6", "CCTV6World", "CCTV7",
"CCTV8", "CCTV9World", "CCTVA", "CCTVChild", "CCTVE", "CCTVEN", "CCTVF", "CCTVFYYY",
"CCTVHJJC", "CCTVMusic", "CCTVNEWS", "CCTVR", "CETV1", "CETV3", "ChongQingTV", "ChongQingWorld",
"GZChild", "GZEnglish", "GZFinance", "GZJingSai", "GZMovie", "GanSuTV", "GuangXiTV", "GuiZhouTV",
]
host = '10.160.1.21'
date = '2014/10/31'
bitrates = ['800000']
channel = random.choice(channels)
bitrate = random.choice(bitrates)
ts_url = ''.join(
['http://', host, '/', 'online01/stream/', bitrate, '/', channel, '/', date, '/', random_str()])
return ts_url
def generate_random_ip():
RANDOM_IP_POOL = ['192.168.10.222/0']
str_ip = RANDOM_IP_POOL[random.randint(0, len(RANDOM_IP_POOL) - 1)]
str_ip_addr = str_ip.split('/')[0]
str_ip_mask = str_ip.split('/')[1]
ip_addr = struct.unpack('>I', socket.inet_aton(str_ip_addr))[0]
mask = 0x0
for i in range(31, 31 - int(str_ip_mask), -1):
mask = mask | (1 << i)
ip_addr_min = ip_addr & (mask & 0xffffffff)
ip_addr_max = ip_addr | (~mask & 0xffffffff)
return socket.inet_ntoa(struct.pack('>I', random.randint(ip_addr_min, ip_addr_max)))
def generate_random_province():
provinces = ['河北省', '山西省', '辽宁省', '吉林省', '黑龙江省', '江苏省', '浙江省', '安徽省', '福建省',
'江西省', '山东省', '河南省', '湖北省', '湖南省', '广东省', '海南省', '四川省', '贵州省',
'云南省', '陕西省', '甘肃省', '青海省', '台湾省', '上海市', '北京市', '天津市', '重庆市',
'香港', '澳门']
return provinces[random.randint(0, len(provinces) - 1)]
def generate_shop_id():
shop_no = ['A', 'B', 'C', 'D', 'F', 'F', 'G']
return shop_no[random.randint(0, len(shop_no) - 1)] + str(random.randint(1, 9999))
def mock_user_data():
session_id = uuid.uuid4()
cookie_id = uuid.uuid4()
visit_time = generate_random_time()
user_id = generate_random_user_id()
age = str(random.randint(10, 80))
sex = 'F' if random.randint(0, 1) == 1 else 'M'
visit_url = generate_random_url()
visit_os = 'Windows OS' if random.randint(0, 1) == 1 else 'Mac OS'
browser_name = 'Google' if random.randint(0, 1) == 1 else 'IE'
visit_ip = generate_random_ip()
province = generate_random_province()
city = province
page_id = str(random.randint(1, 99999))
goods_id = str(random.randint(1, 999999999))
shop_id = generate_shop_id()
return "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s" \
% (session_id, cookie_id, visit_time, user_id, age, sex, visit_url,
visit_os, browser_name, visit_ip, province, city,
page_id, goods_id, shop_id)
def create_data(rows=5000000):
for i in range(rows):
with open('user.csv', 'a')as f:
f.write(mock_user_data() + "\n")
create_data()
Phoenix 导出csv文件
https://dandelioncloud.cn/article/details/1561504709800587266
https://blog.csdn.net/u012581453/article/details/132428992
source bigdata_env -- 环境认证
kinit -kt admin.keytab admin -- 用户认证
-- 设置客户端宽度
!set maxwidth 3000
-- 让结果竖着显示
!set outputformat vertical
!set outputformat table
-- 设置数据导出格式
!outputformat csv
-- 设置导出数据的存储位置
!record /home/test/result.csv
-- 查询数据
select * from test;
-- 结束导出
!record
!tables


浙公网安备 33010602011771号