热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

[翻译]HivewikiGettingStarted

2019独角兽企业重金招聘Python工程师标准##安装和配置需求java1.6hadoop0.20.x使用发布包安装Hive首先从Apache下载镜像下载最新的发布包(见H

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

##安装和配置

需求

  • java1.6
  • hadoop 0.20.x

使用发布包安装Hive

首先从Apache下载镜像下载最新的发布包(见Hive版本) 接下来解压缩tar包。这将会创建一个名字为hive-x.y.z的子目录

$ tar -xzvf hive-x.y.z.tar.gz

配置环境变量HIVE_HOME 指向安装的目录:

$ cd hive-x.y.z
$ export HIVE_HOME={{pwd}}

最后,添加$HIVE_HOME/bin 到PATH:

$ export PATH=$HIVE_HOME/bin:$PATH

###从源码创建Hive Hive SVN地址:http://svn.apache.org/repos/asf/hive/trunk

$ svn co http://svn.apache.org/repos/asf/hive/trunk hive
$ cd hive
$ ant clean package
$ cd build/dist
$ ls
README.txt
bin/ (all the shell scripts)
lib/ (required jar files)
conf/ (configuration files)
examples/ (sample input and query files)

接下来我们会交替使用build/dist和. ###使用hadoop0.23.3编译Hive

$ svn co http://svn.apache.org/repos/asf/hive/trunk hive
$ cd hive
$ ant clean package -Dhadoop.version=0.23.3 -Dhadoop-0.23.version=0.23.3 -Dhadoop.mr.rev=23
$ ant clean package -Dhadoop.version=2.0.0-alpha -Dhadoop-0.23.version=2.0.0-alpha -Dhadoop.mr.rev=23

###运行Hive Hive使用了Hadoop,因此:

  • 你必须配置Hadoop环境变量信息,或者
  • export HADOOP_HOME=

另外,你在Hive中创建表前必须在HDFS上创建/tmp和/user/hive/warehouse(见hive.metastore.warehouse.dir)目录,并且设置权限为 chmod g+w 完成这个步骤的命令:

$ $HADOOP_HOME/bin/hadoop fs -mkdir /tmp
$ $HADOOP_HOME/bin/hadoop fs -mkdir /user/hive/warehouse
$ $HADOOP_HOME/bin/hadoop fs -chmod g+w /tmp
$ $HADOOP_HOME/bin/hadoop fs -chmod g+w /user/hive/warehouse

设置HIVE_HOME,虽然不是必须的,但是很有用

$ export HIVE_HOME=

从shell使用Hive命令行工具(CLI)

$ $HIVE_HOME/bin/hive

###运行HCatalog

从shell运行HCatalog,Hive0.11.0及以后版本:

$ $HIVE_HOME/hcatalog/sbin/hcat_server.sh

使用HCatalog命令行工具(CLI),Hive0.11.0及以后版本: $ $HIVE_HOME/hcatalog/bin/hcat 更多信息,见HCatalog手册中的从TAR包安装HCatalog和HCatalog CLI ###运行WebHCat 从shell运行WebCat server,Hive0.11.0及以后版本: $ $HIVE_HOME/hcatalog/sbin/webhcat_server.sh 更多信息 见WebHCat手册的安装WebHCat

###配置管理概述

  • Hive默认配置/conf/hive-default.xml
  • 可以通过设置HIVE_CONF_DIR环境变量来改变Hive配置目录
  • 使用/conf/hive-site.xml来修改配置信息
  • Log4j配置信息存放在/conf/hive-log4j.properties
  • Hive配置会覆盖Hadoop配置-即默认Hive会继承Hadoop的配置信息
  • 操作Hive配置的方式:
    • 编辑hive-site.xml,定义任何需要的变量(包括Hadoop变量)
    • 通过CLI使用set命令(见下面)
    • 使用如下语法运行hive
      • $ bin/hive -hiveconf x1=y1 -hiveconf x2=y2 这会设置变量x1和x2分别为y1和y2
    • 通过设置HIVE_OPTS环境变量为"-hiveconf x1=y1 -hiveconf x2=y2"和上面功能一样.

###运行时配置

  • Hive查询是执行map-reduce查询,因此这些查询可以通过Hadoop配置变量来控制

  • CLI命令'SET'可以设置任意Hadoop(或者Hive)配置变量,如:

    hive> SET mapred.job.tracker=myhost.mycompany.com:50030; hive> SET -v;

后者显示当前所有配置,不使用-v参数则显示与Hadoop不同的配置。

Hive,Map-Reduce和Local-Mode

Hive编译器将大多数查询生成为map-reduce的jobs。这些jobs提交到由变量指定的Map-Reduce集群 mapred.job.tracker 这通常指向多节点的map-reduce集群,Hadoop也提供了一个选项在本地用户机器上运行map-reduce jobs.在小数据集上运行查询时会非常有用-在这种情况下,local mode执行通常会比提交到大集群明显加快。可以从HDFS透明访问数据,相反,local mode只运行一个reducer,在大数据集是将会非常慢。

从0.7版本开始,Hive完美提供了local mode运行。用户通过配置如下参数来生效

hive> SET mapred.job.tracker=local;

另外,mapred.local.dir指向本地机器的有效路径(如:/tmp//mapred/local).(否则用户将会收到分配本地磁盘空间的异常) 从0.7版本开始,Hive也提供了自动使用local mode来运行map-reduce jobs。相关选项为hive.exec.mode.local.auto,hive.exec.mode.local.auto.imputbytes.max和hive.exec.mode.local.auto.tasks.max:

hive> SET hive.exec.mode.local.auto=false;

该特性默认是失效的.如果生效,Hive分析查询中各个map-reduce job的大小,当满足下述所有条件时运行本地模式:

  • 作业总计输入大小小于:hive.exec.mode.local.auto.inputbytes.max (默认128MB)
  • map-tasks总数小于:hive.exec.mode.local.auto.tasks.max (4 by default)
  • reduce tasks总数为1或者0.

因此在小数据集上查询,或者查询在多个map-reduce jobs但是jobs大体上很小,作业会运行在本地模式。

由于可能Hadoop服务器节点和Hive客户端机器的运行环境不同(因为不同的jvm版本或者不同的软件库)。在本地模式运行时,会产生意想不到的行为或错误。同样本地模式是在一个独立的子jvm(Hive的客户端)运行,如果用户期望,子jvm所能使用的最大内存量,可以通过hive.mapred.local.mem选项来控制,默认值为0,在此情况下Hive让Hadoop决定子jvm的默认内存限制。

###错误日志

Hive使用log4j来记录日志,默认CLI不会输出日志到控制台。默认日志级别为WARN在Hive0.13.0版本之前。从Hive0.13.0版本开始,默认日志级别为INFO。日志存放文件夹:

  • /tmp//hive.log 注解:在本地模式,日志文件名为".log"而不是"hive.log".这是一个bug将会在0.13.0版本修复(见 HIVE-5528 和 HIVE-5676).

如果用户希望-日志可以输出到控制台,通过添加如下参数: bin/hive -hiveconf hive.root.logger=INFO,console 另外,用户可以修改日志级别: bin/hive -hiveconf hive.root.logger=INFO,DRFA

注意在hive初始化后通过‘set'命令来修改hive.root.logger不会修改日志属性。

同样Hive会为每个session保存查询日志在/tmp//,但是可以通过配置hive-site.xml中的hive.querylog.location属性。

Hive在一个hadoop集群上运行过程中的日志是由Hadoop的配置所决定的。通常Hadoop会对每个map和reduce task产生一个日志文件,并保存在运行任务的集群机器上。通过Hadoop JobTracker WEB界面的任务明细页面来获取日志文件。

使用本地模式时(使用mapred.job.tracker=local),Hadoop/Hive会将执行日志放在本机上,从0.6版本开始,Hive使用 hive-exec-log4j.properties(不存在则使用hive-log4j.properties ) 来定义默认日志定义。默认配置文件为每个查询生成单独日志文件在本地模式下并存放在/tmp/。提供单独的配置文件是为了允许管理员在需要的时候集中运行日志(如:放在NFS文件系统上).执行日志对调试运行错误很有用。

WebHCat的错误和日志,见 Error Codes and Responses 和 Log Files 在 WebHCat manual.

错误日志对调试问题非常有用,请提交它们和bugs到hive-dev@hadoop.apache.org.

###审计日志

审计日志记录来自于Hive metastore服务器的每个metastore API调用。

审计日志记录了函数和相关的函数参数在metastore日志文件中。日志的记录级别为log4j的INFO。因此你必须确定INFO级别的日志是启用的(见HIVE-3505).日志的入口名称为”HiveMetaStore.audit".

审计日志在Hive0.7版本添加,用于安全的客户端连接(HIVE-1948)和Hive0.10版本的非安全连接 (HIVE-3277; 也见 HIVE-2797).

##DDL操作

Hive DDL操作文档:Hive Data Definition Language.

###创建Hive表

hive> CREATE TABLE pokes (foo INT, bar STRING);

创建有2个字段的pokes表,第一个字段类型为integer另一个为string。

hive> CREATE TABLE invites (foo INT, bar STRING) PARTITIONED BY (ds STRING);

创建一个名为invites的表,有2个字段和一个名为ds的分区字段,分区字段是一个虚拟字段。它不是数据本身的一部分。但是来源于特定数据集装入的分区。 默认,表假定输入格式为纯文本和分隔符为^A(ctrl-a).

###浏览表

hive> SHOW TABLES;

列出所有表

hive> SHOW TABLES '.*s';

列出所有以's'结尾的表。模式匹配使用Java的正则表达式。文档参见:http://java.sun.com/javase/6/docs/api/java/util/regex/Pattern.html.

hive> DESCRIBE invites;

显示表invites的字段。

###变更和删除表

可以修改表名和添加或替换字段

hive> ALTER TABLE events RENAME TO 3koobecaf;
hive> ALTER TABLE pokes ADD COLUMNS (new_col INT);
hive> ALTER TABLE invites ADD COLUMNS (new_col2 INT COMMENT 'a comment');
hive> ALTER TABLE invites REPLACE COLUMNS (foo INT, bar STRING, baz INT COMMENT 'baz replaces new_col2');

注意:REPLACE COLUMNS 替换所有存在的字段和只修改表定义.不修改数据。表必须使用native SerDe.(注:不清楚这里指什么).REPLACE COLUMNS也可用于从表定义中删除字段。

hive> ALTER TABLE invites REPLACE COLUMNS (foo INT COMMENT 'only keep the first column');

删除表:

hive> DROP TABLE pokes;

###元数据存储

元数据存储在内嵌的Derby数据库,其磁盘存放路径由Hive配置变量javax.jdo.option.ConnectionURL定义.默认路径为./metastore_db(见conf/hive-default.xml).

现在,在默认配置中,该元数据每次只能被一个用户访问。

元数据能存放在任意支持JPOX的数据库中,数据库路径和类型由参数javax.jdo.option.ConnectionURL和javax.jdo.option.ConnectionDriverName控制。见JDO(或JPOX)文档了解支持的数据库。数据库表定义定义在 src/contrib/hive/metastore/src/model目录下的JDO元数据文件package.jdo。

在将来,元数据本身将会成为一个单独的服务。

如果你想将元数据运行为网络服务,从而能够被多个节点访问,见 Hive Using Derby in Server Mode.

###DML操作

Hive DML操作见文档Hive Data Manipulation Language. 从文件导入数据到Hive

hive> LOAD DATA LOCAL INPATH './examples/files/kv1.txt' OVERWRITE INTO TABLE pokes;

装载由ctrl-a分隔包括2个字段的文件到pokes表。'LOCAL'指示输入文件在本地文件系统,如果省略'LOCAL'将会在HDFS上寻找文件。

关键字'OVERWRITE'指示删除表中已经存在的数据。如果省略'OVERWRITE',数据文件将会追加到存在的数据集中。 注意:

  • load命令不会校验数据与表定义是否一致。

  • 如果文件在hdfs上,将会移动到Hive管理的文件系统空间。 Hive的根目录由文件hive-default.xml中的选项 option hive.metastore.warehouse.dir定义。我们建议用户在Hive中创建表前先建立这个目录。

    hive> LOAD DATA LOCAL INPATH './examples/files/kv2.txt' OVERWRITE INTO TABLE invites PARTITION (ds='2008-08-15'); hive> LOAD DATA LOCAL INPATH './examples/files/kv3.txt' OVERWRITE INTO TABLE invites PARTITION (ds='2008-08-08');

上面的这2个LOAD语句装载数据到表invites的2个不同的分区。表invites必须先创建同样的ds键的分区来成功运行语句。 hive> LOAD DATA INPATH '/user/myname/kv2.txt' OVERWRITE INTO TABLE invites PARTITION (ds='2008-08-15');

上述命令将从HDFS文件目录装载数据到表。 注意从HDFS装载数据将会移动文件/目录。该操作几乎是同时的。

##SQL操作 Hive查询操作见文档Select.

###查询示例

下面展示一些查询例子,它们也在build/dist/examples/queries. 更多的在Hive源代码ql/src/test/queries/positive.

####SELECTS and FILTERS

hive> SELECT a.foo FROM invites a WHERE a.ds='2008-08-15';

查询invites表ds=2008-08-15分区上的'foo'字段的所有记录。结果将会直接显示在控制台上。

在下面的所有例子中,INSERT(到Hive表,本地目录或者HDFS目录)是可选的。

hive> INSERT OVERWRITE DIRECTORY '/tmp/hdfs_out' SELECT a.* FROM invites a WHERE a.ds='2008-08-15';

查询invites表ds=2008-08-15分区的所有记录结果导出到HDFS的目录。查询结果数据在那个目录下的多个文件(依赖于mappers的个数)。

注意:如果任何查询使用*,分区字段也会显示在查询结果中。

分区表必须在查询的WHERE子句中指定。

hive> INSERT OVERWRITE LOCAL DIRECTORY '/tmp/local_out' SELECT a.* FROM pokes a;

查询pokes表的所有记录到处到本地目录/tmp/local_out

hive> INSERT OVERWRITE TABLE events SELECT a.* FROM profiles a;
hive> INSERT OVERWRITE TABLE events SELECT a.* FROM profiles a WHERE a.key <100;
hive> INSERT OVERWRITE LOCAL DIRECTORY &#39;/tmp/reg_3&#39; SELECT a.* FROM events a;
hive> INSERT OVERWRITE DIRECTORY &#39;/tmp/reg_4&#39; select a.invites, a.pokes FROM profiles a;
hive> INSERT OVERWRITE DIRECTORY &#39;/tmp/reg_5&#39; SELECT COUNT(*) FROM invites a WHERE a.ds&#61;&#39;2008-08-15&#39;;
hive> INSERT OVERWRITE DIRECTORY &#39;/tmp/reg_5&#39; SELECT a.foo, a.bar FROM invites a;
hive> INSERT OVERWRITE LOCAL DIRECTORY &#39;/tmp/sum&#39; SELECT SUM(a.pc) FROM pc1 a;

查询字段的SUM&#xff0c;或者使用avg、min或者max。注意不包含在HIVE-287的Hive的版本,你需要使用COUNT(1)来替换COUNT(*).

####GROUP BY

hive> FROM invites a INSERT OVERWRITE TABLE events SELECT a.bar, count(*) WHERE a.foo > 0 GROUP BY a.bar;
hive> INSERT OVERWRITE TABLE events SELECT a.bar, count(*) FROM invites a WHERE a.foo > 0 GROUP BY a.bar;

注意不包含在HIVE-287的Hive的版本,你需要使用COUNT(1)来替换COUNT(*).

####JOIN

hive> FROM pokes t1 JOIN invites t2 ON (t1.bar &#61; t2.bar) INSERT OVERWRITE TABLE events SELECT t1.bar, t1.foo, t2.foo;

####MULTITABLE INSERT

FROM src
INSERT OVERWRITE TABLE dest1 SELECT src.* WHERE src.key <100
INSERT OVERWRITE TABLE dest2 SELECT src.key, src.value WHERE src.key >&#61; 100 and src.key <200
INSERT OVERWRITE TABLE dest3 PARTITION(ds&#61;&#39;2008-04-08&#39;, hr&#61;&#39;12&#39;) SELECT src.key WHERE src.key >&#61; 200 and src.key <300
INSERT OVERWRITE LOCAL DIRECTORY &#39;/tmp/dest4.out&#39; SELECT src.value WHERE src.key >&#61; 300;

####STREAMING

hive> FROM invites a INSERT OVERWRITE TABLE events SELECT TRANSFORM(a.foo, a.bar) AS (oof, rab) USING &#39;/bin/cat&#39; WHERE a.ds > &#39;2008-08-09&#39;;

在map阶段的数据流通过脚本 /bin/cat (like Hadoop streaming). 同样的&#xff0c;在reduce也可以使用数据流(例子见Hive Tutorial )

##场景例子

###电影评级

首先&#xff0c;建立一张tab键分隔的文本格式的表

CREATE TABLE u_data (userid INT,movieid INT,rating INT,unixtime STRING)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY &#39;\t&#39;
STORED AS TEXTFILE;

接下来下载和提取数据文件

wget http://www.grouplens.org/sites/www.grouplens.org/external_files/data/ml-data.tar.gz tar xvzf ml-data.tar.gz

装载数据到表 LOAD DATA LOCAL INPATH &#39;ml-data/u.data&#39; OVERWRITE INTO TABLE u_data;

统计表u_data的记录数

SELECT COUNT(*) FROM u_data;

注意&#xff1a;不包含在 HIVE-287中的Hive版本需要使用COUNT(1)而不是COUNT(*) 现在我们在表u_data上来做一些复杂的数据分析 创建weekday_mapper.py:

import sys
import datetimefor line in sys.stdin:line &#61; line.strip()userid, movieid, rating, unixtime &#61; line.split(&#39;\t&#39;)weekday &#61; datetime.datetime.fromtimestamp(float(unixtime)).isoweekday()print &#39;\t&#39;.join([userid, movieid, rating, str(weekday)])

使用mapper脚本&#xff1a;

CREATE TABLE u_data_new (userid INT,movieid INT,rating INT,weekday INT)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY &#39;\t&#39;;add FILE weekday_mapper.py;INSERT OVERWRITE TABLE u_data_new
SELECTTRANSFORM (userid, movieid, rating, unixtime)USING &#39;python weekday_mapper.py&#39;AS (userid, movieid, rating, weekday)
FROM u_data;SELECT weekday, COUNT(*)
FROM u_data_new
GROUP BY weekday;

注意如果你使用Hive0.5.0或更早版本&#xff0c;你需要使用COUNT(1)而不是COUNT(*).

###Apache Weblog Data Apache weblog的格式是可定制的&#xff0c;大多数web管理员使用默认配置。 默认Apache weblog&#xff0c;我们创建表使用下面的命令

关于!RegexSerDe的信息见HIVE-662 and HIVE-1719.

CREATE TABLE apachelog (host STRING,identity STRING,user STRING,time STRING,request STRING,status STRING,size STRING,referer STRING,agent STRING)
ROW FORMAT SERDE &#39;org.apache.hadoop.hive.serde2.RegexSerDe&#39;
WITH SERDEPROPERTIES ("input.regex" &#61; "([^]*) ([^]*) ([^]*) (-|\\[^\\]*\\]) ([^ \"]*|\"[^\"]*\") (-|[0-9]*) (-|[0-9]*)(?: ([^ \"]*|\".*\") ([^ \"]*|\".*\"))?"
)
STORED AS TEXTFILE;

参考&#xff1a; https://cwiki.apache.org/confluence/display/Hive/GettingStarted


转:https://my.oschina.net/xiangel/blog/209822



推荐阅读
  • javascript分页类支持页码格式
    前端时间因为项目需要,要对一个产品下所有的附属图片进行分页显示,没考虑ajax一张张请求,所以干脆一次性全部把图片out,然 ... [详细]
  • 本文详细介绍了如何在 Linux 系统上安装 JDK 1.8、MySQL 和 Redis,并提供了相应的环境配置和验证步骤。 ... [详细]
  • 为了在Hadoop 2.7.2中实现对Snappy压缩和解压功能的原生支持,本文详细介绍了如何重新编译Hadoop源代码,并优化其Native编译过程。通过这一优化,可以显著提升数据处理的效率和性能。此外,还探讨了编译过程中可能遇到的问题及其解决方案,为用户提供了一套完整的操作指南。 ... [详细]
  • Web开发框架概览:Java与JavaScript技术及框架综述
    Web开发涉及服务器端和客户端的协同工作。在服务器端,Java是一种优秀的编程语言,适用于构建各种功能模块,如通过Servlet实现特定服务。客户端则主要依赖HTML进行内容展示,同时借助JavaScript增强交互性和动态效果。此外,现代Web开发还广泛使用各种框架和库,如Spring Boot、React和Vue.js,以提高开发效率和应用性能。 ... [详细]
  • Spring Boot 中配置全局文件上传路径并实现文件上传功能
    本文介绍如何在 Spring Boot 项目中配置全局文件上传路径,并通过读取配置项实现文件上传功能。通过这种方式,可以更好地管理和维护文件路径。 ... [详细]
  • 本文回顾了作者初次接触Unicode编码时的经历,并详细探讨了ASCII、ANSI、GB2312、UNICODE以及UTF-8和UTF-16编码的区别和应用场景。通过实例分析,帮助读者更好地理解和使用这些编码。 ... [详细]
  • 零拷贝技术是提高I/O性能的重要手段,常用于Java NIO、Netty、Kafka等框架中。本文将详细解析零拷贝技术的原理及其应用。 ... [详细]
  • 探索Web 2.0新概念:Widget
    尽管你可能尚未注意到Widget,但正如几年前对RSS的陌生一样,这一概念正逐渐走入大众视野。据美国某权威杂志预测,2007年将是Widget年。本文将详细介绍Widget的定义、功能及其未来发展趋势。 ... [详细]
  • [转]doc,ppt,xls文件格式转PDF格式http:blog.csdn.netlee353086articledetails7920355确实好用。需要注意的是#import ... [详细]
  • 在Delphi7下要制作系统托盘,只能制作一个比较简单的系统托盘,因为ShellAPI文件定义的TNotifyIconData结构体是比较早的版本。定义如下:1234 ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • 如何将TS文件转换为M3U8直播流:HLS与M3U8格式详解
    在视频传输领域,MP4虽然常见,但在直播场景中直接使用MP4格式存在诸多问题。例如,MP4文件的头部信息(如ftyp、moov)较大,导致初始加载时间较长,影响用户体验。相比之下,HLS(HTTP Live Streaming)协议及其M3U8格式更具优势。HLS通过将视频切分成多个小片段,并生成一个M3U8播放列表文件,实现低延迟和高稳定性。本文详细介绍了如何将TS文件转换为M3U8直播流,包括技术原理和具体操作步骤,帮助读者更好地理解和应用这一技术。 ... [详细]
  • Hadoop平台警告解决:无法加载本机Hadoop库的全面应对方案
    本文探讨了在Hadoop平台上遇到“无法加载本机Hadoop库”警告的多种解决方案。首先,通过修改日志配置文件来忽略该警告,这一方法被证明是有效的。其次,尝试指定本地库的路径,但未能解决问题。接着,尝试不使用Hadoop本地库,同样没有效果。然后,通过替换现有的Hadoop本地库,成功解决了问题。最后,根据Hadoop的源代码自行编译本地库,也达到了预期的效果。以上方法适用于macOS系统。 ... [详细]
  • 本文将继续探讨 JavaScript 函数式编程的高级技巧及其实际应用。通过一个具体的寻路算法示例,我们将深入分析如何利用函数式编程的思想解决复杂问题。示例中,节点之间的连线代表路径,连线上的数字表示两点间的距离。我们将详细讲解如何通过递归和高阶函数等技术实现高效的寻路算法。 ... [详细]
  • 本文详细介绍了在Linux系统上编译安装MySQL 5.5源码的步骤。首先,通过Yum安装必要的依赖软件包,如GCC、GCC-C++等,确保编译环境的完备。接着,下载并解压MySQL 5.5的源码包,配置编译选项,进行编译和安装。最后,完成安装后,进行基本的配置和启动测试,确保MySQL服务正常运行。 ... [详细]
author-avatar
o0大大脸么么小小鱼0o
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有