当前位置:  数据库>nosql
本页文章导读:
    ▪MongoDB 聚合      MongoDB除了基本的查询功能,还提供了很多强大的聚合工具,其中简单的可计算集合中的文档个数,复杂的可利用MapReduce做复杂数据分析. 1.countcount返回集合中的文档数量db.refactor.count()不管集合.........
    ▪NoSQL生态系统        NoSQL不是一个工具,而是由一些具有互补性和竞争性的工具组成的一个概念,是一个生态圈。这些被称作NoSQL的工具,在存储数据的方式上,提供了一种与基于SQL语言的关系型数据截然不.........
    ▪NoSQL生态系统        NoSQL不是一个工具,而是由一些具有互补性和竞争性的工具组成的一个概念,是一个生态圈。这些被称作NoSQL的工具,在存储数据的方式上,提供了一种与基于SQL语言的关系型数据截然不.........

[1]MongoDB 聚合
    来源:    发布时间: 2013-10-18

MongoDB除了基本的查询功能,还提供了很多强大的聚合工具,其中简单的可计算集合中的文档个数,

复杂的可利用MapReduce做复杂数据分析.

 

1.count

count返回集合中的文档数量

db.refactor.count()

不管集合有多大,都能很快的返回文档数量.

可以传递查询,MongoDB会计算查询结果的数量

db.refactor.count({"username":"refactor"})

但是增加查询条件会使count变慢.

 

2.distinct

distinct用来找出给定键的所有不同值.使用时必须指定集合和键.

如:

db.runCommand({"distinct":"refactor","key":"username"})

 

 3.group

group先选定分组所依据的键,MongoDB将会将集合依据选定键值的不同分成若干组.然后可以通过聚合每一组内的文档,

产生一个结果文档.

如:

db.runCommand(
{
  "group":
  {
    "ns":"refactor",
    "key":{"username":true},
    "initial":{"count":0},
    "$reduce":function(doc,prev)
    {
      prev.count++;
    },
    "condition":{"age":{"$gt":40}}
  }
}
)

   "ns":"refactor",

指定要进行分组的集合
    "key":{"username":true},

指定文档分组的依据,这里是username键,所有username键的值相等的被划分到一组,true为返回键username的值
    "initial":{"count":0},

每一组reduce函数调用的初始个数.每一组的所有成员都会使用这个累加器.
    "$reduce":function(doc,prev){...}

每个文档都对应的调用一次.系统会传递两个参数:当前文档和累加器文档.

"condition":{"age":{"$gt":40}}

这个age的值大于40的条件

 

4.使用完成器

完成器用于精简从数据库传到用户的数据.group命令的输出一定要能放在单个数据库相应中.

"finalize"附带一个函数,在数组结果传递到客户端之前被调用一次.

db.runCommand(
  {
    "group":
    {
      "ns":"refactor",
      "key":{"username":true},
      "initial":{"count":0},
      "$reduce":function(doc,prev)
      {
        prev.count++;
      },
      "finalize":function(doc)
      {
        doc.num=doc.count;
        delete doc.count;
      }
    }
  }
)

finalize能修改传递的参数也能返回新值.

 

5.将数组作为键使用

有些时候分组所依据的条件很复杂,不仅是一个键.比如要使用group计算每个类别有多篇博客文章.由于有很多作者,

给文章分类时可能不规律的使用了大小写.所以,如果要是按类别名来分组,最后"MongoDB"和"mongodb"就是不同的组.

为了消除这种大小写的影响,就要定义一个函数来确定文档所依据的键.

定义分组要用到$keyf

db.runCommand(
 {
  "group":
   {
    "ns":"refactor",
    "$keyf":function(doc){return {"username":doc.username.toLowerCase()}},
    "initial":{"count":0},
    "$reduce":function(doc,prev)
       {
        prev.count++;
       }
   }
 }
)

 

6.MapReduce

count,distinct,group能做的事情MapReduce都能做.它是一个可以轻松并行化到多个服务器的聚合方法.它会

拆分问题,再将各个部分发送到不同机器上,让每台机器完成一部分.当所有机器都完成时候,再把结果汇集起来形成

最终完整的结果.

MapReduce需要几个步骤:

1.映射,将操作映射到集合中的每个文档.这个操作要么什么都不做,要么 产生一个键和n个值.

2.洗牌,按照键分组,并将产生的键值组成列表放到对应键中.

3.化简,把列表中的值 化简 成一个单值,这个值被返回.

4.重新洗牌,直到每个键的列表只有一个值为止,这个值就是最终结果.

MapReduce的速度比group慢,group也很慢.在应用程序中,最好不要用MapReduce,可以在后台运行MapReduce

创建一个保存结果的集合,可以对这个集合进行实时查询.

 

找出集合中的所有键

MongoDB没有模式,所以并不知晓每个文档有多少个键.通常找到集合的所有键的做好方式是用MapReduce.

在映射阶段,想得到文档中的每个键.map函数使用emit 返回要处理的值.emit会给MapReduce一个键和一个值.

这里用emit将文档某个键的记数(count)返回({count:1}).我们为每个键单独记数,所以为文档中的每一个键调用一次emit,

this是当前文档的引用:

map=function(){
  for(var key in this)
  {
    emit(key,{count:1})
  }
};

这样返回了许许多多的{count:1}文档,每一个都与集合中的一个键相关.这种有一个或多个{count:1}文档组成的数组,

会传递给reduce函数.reduce函数有两个参数,一个是key,也就是emit返回的第一个值,另一个参数是数组,由一个或者多个

对应键的{count:1}文档组成.

reduce=function(key,emits){
  total=0;
  for(var i in emits){
    total+=emits[i].count;
  }
  return {count:total};
}

reduce要能被反复被调用,不论是映射环节还是前一个化简环节.reduce返回的文档必须能作为reduce的

第二个参数的一个元素.如x键映射到了3个文档{"count":1,id:1},{"count":1,id:2},{"count":1,id:3}

其中id键用于区别.MongoDB可能这样调用reduce:

>r1=reduce("x",[{"count":1,id:1},{"count":1,id:2}])

{count:2}

>r2=reduce("x",[{"count":1,id:3}])

{count:1}

>reduce("x",[r1,r2])

{count:3}

reduce应该能处理emit文档和其他reduce结果的各种集合.

如:

mr=db.runCommand(
  {
  "mapreduce":"refactor",
  "map":map,
  "reduce":reduce,
  "out":{inline:1}
  }
)

或:

db.refactor.mapReduce(map,reduce,{out:{inline:1}})

"timeMillis" : 5,//操作花费的时间
"counts" : {
"input" : 10,//发往到map函数的文档个数
"emit" : 40,//在map函数中emit被调用的次数
"reduce" : 4,//在map函数中reduce被调用的次数
"output" : 4//结果集合中创建的文档数量.
},

1.mapreduce是根据map函数里调用的emit函数的第一个参数来进行分组的
2.仅当根据分组键分组后一个键匹配多个文档,才会将key和文档集合交由reduce函数处理

注意MongoDB 1.8版本以上,必须指明 out 参数

否则会报如下错误:

"assertion" : "'out' has to be a string or an object",
"assertionCode" : 13606,

 

MapReduce中的其他键

mapreduce,map,reduce这三个键是必须的,MapReduce命令还有其他的可选键

finalize:函数

将reduce的结果发送给这个键,这是处理过程的最后一步

keeptemp:布尔值

连接关闭时,临时结果是否保存

output:字符串

结果集合的名字,设定该项则隐含着keeptemp:true

query:文档

会在发往map函数前,先用指定条件过滤文档

sort:文档

会在发往map函数前先给文档排序

limit:整数

发往map函数文档的最大数量

scope:文档

javascript代码中要用到的变量

verbose:布尔值

是否产生更加信息的服务器日志 

本文链接


    
[2]NoSQL生态系统
    来源:    发布时间: 2013-10-18

  NoSQL不是一个工具,而是由一些具有互补性和竞争性的工具组成的一个概念,是一个生态圈。这些被称作NoSQL的工具,在存储数据的方式上,提供了一种与基于SQL语言的关系型数据截然不同的思路。要想了解NoSQL,我们必须先了解现有的这些工具,去理解那些让他们开拓出新的存储领域的设计思路。

如果你正在考虑使用NoSQL,你应该会马上发现你有很多种选择。NoSQL系统舍弃了许了传统关系型数据库的方便之处,而把一些通常由关系型数据库本身来完成的任务交给了应用层来完成。这需要开发人员更深入的去了解存储系统的架构和具体实现。
1 NoSQL其名

在给NoSQL下定义之前,我们先来试着从它的名字上做一下解读,顾名思义,NoSQL系统的数据操作接口应该是非SQL类型的。但在NoSQL社区,NoSQL被赋予了更具有包容性的含义,其意为Not Only SQL,即NoSQL提供了一种与传统关系型数据库不太一样的存储模式,这为开发者提供了在关系型数据库之外的另一种选择。有时候你可能会完全用NoSQL数据库代替关系型数据加,但你也可以同时使用关系型和非关系型存储来解决具体的问题。

在进入NoSQL的大门之前,我们先来看看哪些场景下使用关系型数据库更合适,哪些使用NoSQL更合适。

1.1 SQL及其关联型结构

SQL是一种任务描述性的查询语言,所谓任务描述性的查询语言,就是说它只描述他需要系统做什么,而不告诉系统如何去做。例如:查出39号员工的信息,查出员工的名字和电话,只查找做会计工作的员工信息,计算出每个部门的员工总数,或者是对员工表和经理表做一个联合查询。

简单的说,SQL让我们可以直接向数据库提出上述问题而不必考虑数据是如何在磁盘上存储的,使用哪些索引来查询数据,或者说用哪种算法来处理数据。在关系型数据库中有一个重要的组件,叫做查询优化器,正是它来推算用哪种操作方式能够更快的完成操作。查询优化器通常比一般的数据库用户更聪明,但是有时候由于没有充足的信息或者系统模型过于简单,也会导致查询优化器不能得出最有效的操作方式。

作为目前应用最广的数据库系统,关系型数据库系统以其关联型的数据模型而命名。在关联型的数据模型中,在现实世界中的不同类型的个体被存储在不同的表里。比如有一个专门存员工的员工表,有一个专门存部门的部门表。每一行数据又包含多个列,比如员工表里可能包含了员工号,员工工资,生日以及姓名等,这些信息项被存在员工表中的某一列中。

关联型的模型与SQL是紧密想连的。简单的查询操作,比如查询符合某个条件的所有行(例:employeeid = 3, 或者 salary > $20000)。更复杂一些的任务会让数据库做一些额外的工作,比如跨表的联合查询(例:查出3号员的部门名称是什么)。一些复杂的查询,比如统计操作(例:算出所有员工的平均工资),甚至可能会导致全表扫描。

关联型的数据模型定义了高度结构化的数据结构,以及对这些结构之间关系的严格定义。在这样的数据模型上执行的查询操作会比较局限,而且可能会导致复杂的数据遍历操作。数据结构的复杂性及查询的复杂性,会导致系统产生如下的一些限制:

  • 复杂导致不确定性。使用SQL的一个问题就是计算某个查询的代价或者产生的负载几乎是不可能的。使用简单的查询语言可能会导致应用层的逻辑更复杂,但是这样可以将存储系统的工作简单化,让它只需要响应一些简单的请求。
  • 对一个问题建模有很多种方式。其中关联型的数据模型是非常严格的一种:表结构的定义规定了表中每一行数据的存储内容。如果你的数据结构化并没有那么强,或者对每一行数据的要求比较灵活,那可能关联型的数据模型就太过严格了。类似的,应用层的开发人员可能对关联型的数据结构并不满意。比如很多应用程序是用面向对象的语言写的,数据在这些语言中通常是以列表、队列或集合的形式组织的,程序员们当然希望他们的数据存储层也能和应用层的数据模型一致。
  • 当数据量增长到一台机器已经不能容纳,我们需要将不同的数据表分布到不同的机器。而为了避免在不同机器上的数据表在进行联合查询时需要跨网络进行。我们必须进行反范式的数据库设计,这种设计方式要求我们把需要一次性查询到的数据存储在一起。这样做使得我们的系统变得就像一个主键查询系统一样,于是我们开始思考,是否有其它更适合我们数据的数据模型。

通常来说,舍弃多年以来的设计思路是不明智的。当你要把数据存到数据库,当考虑到SQL与关联型的数据模型,这些都是数十年的研究的开发成果,提供丰富的数据模型,提供复杂操作的保证。而当你的问题涉及到大数据量,高负载或者说你的数据结构在SQL与关联型数据模型下很难得到优化,NoSQL可能是更好的选择。

1.2 NoSQL的启示

NoSQL运动受到了很多相关研究论文的启示,这所有论文中,最核心的有两个。

Google的BigTable[CDG+06]提出了一种很有趣的数据模型,它将各列数据进行排序存储。数据值按范围分布在多台机器,数据更新操作有严格的一致性保证。

Amazon的Dynamo[DHJ+07]使用的是另外一种分布式模型。Dynamo的模型更简单,它将数据按key进行hash存储。其数据分片模型有比较强的容灾性,因此它实现的是相对松散的弱一致性:最终一致性。

接下来我们会深入介绍这些设计思想,而实际上在现实中这些思想经常是混搭使用的。比如像HBase及其它一些NoSQL系统他们在设计上更接受BigTable的模型,而像Voldemort 系统它就和Dynamo更像。同时还有像Cassandra这种两种特性都具备的实现(它的数据模型和BigTable类似,分片策略和一致性机制和Dynamo类似)。

1.3 特性概述

NoSQL系统舍弃了一些SQL标准中的功能,取而代之的是提供了一些简单灵活的功能。NoSQL 的构建思想就是尽量简化数据操作,尽量让执行操作的效率可预知。在很多NoSQL系统里,复杂的操作都是留给应用层来做的,这样的结果就是我们对数据层进行的操作得到简化,让操作效率可预知。

NoSQL系统不仅舍弃了很多关系数据库中的操作。它还可能不具备关系数据库以下的一些特性:比如通常银行系统中要求的事务保证,一致性保证以及数据可靠性的保证等。事务机制提供了在执行多个命令时的all-or-nothing保证。一致性保证了如果一个数据更新后,那么在其之后的操作中都能看到这个更新。可靠性保证如果一个数据被更新,它就会被写到持久化的存储设备上(比如说磁盘),并且保证在数据库崩溃后数据可恢复。

通过放宽对上述几点特性的要求,NoSQL系统可以为一些非银行类的业务提供以性能换稳定的策略。而同时,对这几点要求的放宽,又使得NoSQL系统能够轻松的实现分片策略,将远远超出单机容量的大量数据分布在多台机器上的。

由于NoSQL系统还处在萌芽阶段,本章中提到的很多NoSQL架构都是用于满足各种不同用户的需求的。对这些架构进行总结不太可能,因为它们总在变化。所以希望你能记住的一点是,不同的NoSQL系统的特点是不同的,通过本章的内容,希望你能该根据自己的业务情况来选择合适的NoSQL系统,而本章内容不可能给你直接的答案。

当你去考查一个NoSQL系统的时候,下面的的几点是值得注意的:

  • 数据模型及操作模型:你的应用层数据模型是行、对象还是文档型的呢?这个系统是否能支持你进行一些统计工作呢?
  • 可靠性:当你更新数据时,新的数据是否立刻写到持久化存储中去了?新的数据是否同步到多台机器上了?
  • 扩展性:你的数据量有多大,单机是否能容下?你的读写量求单机是否能支持?
  • 分区策略:考虑到你对扩展性,可用性或者持久性的要求,你是否需要一份数据被存在多台机器上?你是否需要知道数据在哪台机器上,以及你能否知道。
  • 一致性:你的数据是否被复制到了多台机器上,这些分布在不同点的数据如何保证一致性?
  • 事务机制:你的业务是否需要ACID的事务机制?
  • 单机性能:如果你打算持久化的将数据存在磁盘上,哪种数据结构能满足你的需求(你的需求是读多还是写多)?写操作是否会成为磁盘瓶颈?
  • 负载可评估:对于一个读多写少的应用,诸如响应用户请求的web应用,我们总会花很多精力来关注负载情况。你可能需要进行数据规模的监控,对多个用户的数据进行汇总统计。你的应用场景是否需要这样的功能呢?

尽管后三点在本章没有独立的小节进行描述,但它们和其它

    
[3]NoSQL生态系统
    来源:    发布时间: 2013-10-18

  NoSQL不是一个工具,而是由一些具有互补性和竞争性的工具组成的一个概念,是一个生态圈。这些被称作NoSQL的工具,在存储数据的方式上,提供了一种与基于SQL语言的关系型数据截然不同的思路。要想了解NoSQL,我们必须先了解现有的这些工具,去理解那些让他们开拓出新的存储领域的设计思路。

如果你正在考虑使用NoSQL,你应该会马上发现你有很多种选择。NoSQL系统舍弃了许了传统关系型数据库的方便之处,而把一些通常由关系型数据库本身来完成的任务交给了应用层来完成。这需要开发人员更深入的去了解存储系统的架构和具体实现。
1 NoSQL其名

在给NoSQL下定义之前,我们先来试着从它的名字上做一下解读,顾名思义,NoSQL系统的数据操作接口应该是非SQL类型的。但在NoSQL社区,NoSQL被赋予了更具有包容性的含义,其意为Not Only SQL,即NoSQL提供了一种与传统关系型数据库不太一样的存储模式,这为开发者提供了在关系型数据库之外的另一种选择。有时候你可能会完全用NoSQL数据库代替关系型数据加,但你也可以同时使用关系型和非关系型存储来解决具体的问题。

在进入NoSQL的大门之前,我们先来看看哪些场景下使用关系型数据库更合适,哪些使用NoSQL更合适。

1.1 SQL及其关联型结构

SQL是一种任务描述性的查询语言,所谓任务描述性的查询语言,就是说它只描述他需要系统做什么,而不告诉系统如何去做。例如:查出39号员工的信息,查出员工的名字和电话,只查找做会计工作的员工信息,计算出每个部门的员工总数,或者是对员工表和经理表做一个联合查询。

简单的说,SQL让我们可以直接向数据库提出上述问题而不必考虑数据是如何在磁盘上存储的,使用哪些索引来查询数据,或者说用哪种算法来处理数据。在关系型数据库中有一个重要的组件,叫做查询优化器,正是它来推算用哪种操作方式能够更快的完成操作。查询优化器通常比一般的数据库用户更聪明,但是有时候由于没有充足的信息或者系统模型过于简单,也会导致查询优化器不能得出最有效的操作方式。

作为目前应用最广的数据库系统,关系型数据库系统以其关联型的数据模型而命名。在关联型的数据模型中,在现实世界中的不同类型的个体被存储在不同的表里。比如有一个专门存员工的员工表,有一个专门存部门的部门表。每一行数据又包含多个列,比如员工表里可能包含了员工号,员工工资,生日以及姓名等,这些信息项被存在员工表中的某一列中。

关联型的模型与SQL是紧密想连的。简单的查询操作,比如查询符合某个条件的所有行(例:employeeid = 3, 或者 salary > $20000)。更复杂一些的任务会让数据库做一些额外的工作,比如跨表的联合查询(例:查出3号员的部门名称是什么)。一些复杂的查询,比如统计操作(例:算出所有员工的平均工资),甚至可能会导致全表扫描。

关联型的数据模型定义了高度结构化的数据结构,以及对这些结构之间关系的严格定义。在这样的数据模型上执行的查询操作会比较局限,而且可能会导致复杂的数据遍历操作。数据结构的复杂性及查询的复杂性,会导致系统产生如下的一些限制:

  • 复杂导致不确定性。使用SQL的一个问题就是计算某个查询的代价或者产生的负载几乎是不可能的。使用简单的查询语言可能会导致应用层的逻辑更复杂,但是这样可以将存储系统的工作简单化,让它只需要响应一些简单的请求。
  • 对一个问题建模有很多种方式。其中关联型的数据模型是非常严格的一种:表结构的定义规定了表中每一行数据的存储内容。如果你的数据结构化并没有那么强,或者对每一行数据的要求比较灵活,那可能关联型的数据模型就太过严格了。类似的,应用层的开发人员可能对关联型的数据结构并不满意。比如很多应用程序是用面向对象的语言写的,数据在这些语言中通常是以列表、队列或集合的形式组织的,程序员们当然希望他们的数据存储层也能和应用层的数据模型一致。
  • 当数据量增长到一台机器已经不能容纳,我们需要将不同的数据表分布到不同的机器。而为了避免在不同机器上的数据表在进行联合查询时需要跨网络进行。我们必须进行反范式的数据库设计,这种设计方式要求我们把需要一次性查询到的数据存储在一起。这样做使得我们的系统变得就像一个主键查询系统一样,于是我们开始思考,是否有其它更适合我们数据的数据模型。

通常来说,舍弃多年以来的设计思路是不明智的。当你要把数据存到数据库,当考虑到SQL与关联型的数据模型,这些都是数十年的研究的开发成果,提供丰富的数据模型,提供复杂操作的保证。而当你的问题涉及到大数据量,高负载或者说你的数据结构在SQL与关联型数据模型下很难得到优化,NoSQL可能是更好的选择。

1.2 NoSQL的启示

NoSQL运动受到了很多相关研究论文的启示,这所有论文中,最核心的有两个。

Google的BigTable[CDG+06]提出了一种很有趣的数据模型,它将各列数据进行排序存储。数据值按范围分布在多台机器,数据更新操作有严格的一致性保证。

Amazon的Dynamo[DHJ+07]使用的是另外一种分布式模型。Dynamo的模型更简单,它将数据按key进行hash存储。其数据分片模型有比较强的容灾性,因此它实现的是相对松散的弱一致性:最终一致性。

接下来我们会深入介绍这些设计思想,而实际上在现实中这些思想经常是混搭使用的。比如像HBase及其它一些NoSQL系统他们在设计上更接受BigTable的模型,而像Voldemort 系统它就和Dynamo更像。同时还有像Cassandra这种两种特性都具备的实现(它的数据模型和BigTable类似,分片策略和一致性机制和Dynamo类似)。

1.3 特性概述

NoSQL系统舍弃了一些SQL标准中的功能,取而代之的是提供了一些简单灵活的功能。NoSQL 的构建思想就是尽量简化数据操作,尽量让执行操作的效率可预知。在很多NoSQL系统里,复杂的操作都是留给应用层来做的,这样的结果就是我们对数据层进行的操作得到简化,让操作效率可预知。

NoSQL系统不仅舍弃了很多关系数据库中的操作。它还可能不具备关系数据库以下的一些特性:比如通常银行系统中要求的事务保证,一致性保证以及数据可靠性的保证等。事务机制提供了在执行多个命令时的all-or-nothing保证。一致性保证了如果一个数据更新后,那么在其之后的操作中都能看到这个更新。可靠性保证如果一个数据被更新,它就会被写到持久化的存储设备上(比如说磁盘),并且保证在数据库崩溃后数据可恢复。

通过放宽对上述几点特性的要求,NoSQL系统可以为一些非银行类的业务提供以性能换稳定的策略。而同时,对这几点要求的放宽,又使得NoSQL系统能够轻松的实现分片策略,将远远超出单机容量的大量数据分布在多台机器上的。

由于NoSQL系统还处在萌芽阶段,本章中提到的很多NoSQL架构都是用于满足各种不同用户的需求的。对这些架构进行总结不太可能,因为它们总在变化。所以希望你能记住的一点是,不同的NoSQL系统的特点是不同的,通过本章的内容,希望你能该根据自己的业务情况来选择合适的NoSQL系统,而本章内容不可能给你直接的答案。

当你去考查一个NoSQL系统的时候,下面的的几点是值得注意的:

  • 数据模型及操作模型:你的应用层数据模型是行、对象还是文档型的呢?这个系统是否能支持你进行一些统计工作呢?
  • 可靠性:当你更新数据时,新的数据是否立刻写到持久化存储中去了?新的数据是否同步到多台机器上了?
  • 扩展性:你的数据量有多大,单机是否能容下?你的读写量求单机是否能支持?
  • 分区策略:考虑到你对扩展性,可用性或者持久性的要求,你是否需要一份数据被存在多台机器上?你是否需要知道数据在哪台机器上,以及你能否知道。
  • 一致性:你的数据是否被复制到了多台机器上,这些分布在不同点的数据如何保证一致性?
  • 事务机制:你的业务是否需要ACID的事务机制?
  • 单机性能:如果你打算持久化的将数据存在磁盘上,哪种数据结构能满足你的需求(你的需求是读多还是写多)?写操作是否会成为磁盘瓶颈?
  • 负载可评估:对于一个读多写少的应用,诸如响应用户请求的web应用,我们总会花很多精力来关注负载情况。你可能需要进行数据规模的监控,对多个用户的数据进行汇总统计。你的应用场景是否需要这样的功能呢?

尽管后三点在本章没有独立的小节进行描述,但它们和其它

    
最新技术文章:
 




特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

网络技术 iis7站长之家