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

每一个Java工程师都应该掌握的全文搜索引擎!

还没关注?快动动手指!

还没关注?

快动动手指!

聊技术、论职场!

为IT人打造一个“有温度”的 狸猫技术窝

最近项目组安排了一个任务,项目中用到了全文搜索,基于全文搜索 Solr

但是该 Solr 搜索云项目不稳定,经常查询不出来数据,需要手动全量同步,而且是其他团队在维护,依赖性太强,导致 Solr 服务一出问题,我们的项目也基本瘫痪,因为所有的依赖查询都无结果数据了。

所以考虑开发一个适配层,如果 Solr 搜索出问题,自动切换到新的搜索:ElasticSearch(ES)

其实可以通过 Solr 集群或者服务容错等设计来解决该问题。但是先不考虑本身设计的合理性,领导需要开发,所以我开始踏上了搭建 ES 服务的道路,从零开始,因为之前完全没接触过 ES,所以通过本系列来记录下自己的开发过程。

什么是全文搜索

首先搞清楚第一个问题: 什么是全文搜索引擎?

百度百科中的定义

全文搜索引擎是目前广泛应用的主流搜索引擎。它的工作原理是计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置

当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。这个过程类似于通过字典中的检索字表查字的过程。

从定义中我们已经可以大致了解全文检索的思路了,为了更详细的说明,我们先从生活中的数据说起。

我们生活中的数据总体分为两种: 结构化数据 和 非结构化数据

  • 结构化数据 : 具有固定格式或有限长度的数据,如数据库,元数据等

  • 非结构化数据 : 非结构化数据又可称为全文数据,指不定长或无固定格式的数据,如邮件,word文档等

当然有的地方还会有第三种: 半结构化数据 ,如XML,HTML等,当根据需要可按结构化数据来处理,也可抽取出纯文本按非结构化数据来处理。

根据两种数据分类,搜索也相应的分为两种:

  • 结构化数据搜索

  • 非结构化数据搜索

对于结构化数据,我们一般都是可以通过关系型数据库(mysql,oracle等)的 table 的方式存储和搜索,也可以建立索引。对于非结构化数据,也即对全文数据的搜索主要有两种方法: 顺序扫描法 全文检索

顺序扫描 :通过文字名称也可了解到它的大概搜索方式,即按照顺序扫描的方式查询特定的关键字。

例如给你一张报纸,让你找到该报纸中“RNG”的文字在哪些地方出现过。你肯定需要从头到尾把报纸阅读扫描一遍然后标记出关键字在哪些版块出现过以及它的出现位置。

这种方式无疑是最耗时的最低效的,如果报纸排版字体小,而且版块较多甚至有多份报纸,等你扫描完你的眼睛也差不多了。

全文搜索 :对非结构化数据顺序扫描很慢,我们是否可以进行优化?把我们的非结构化数据想办法弄得有一定结构不就行了吗?

我们将非结构化数据中的一部分信息提取出来,重新组织,使其变得有一定结构,然后对此有一定结构的数据进行搜索,从而达到搜索相对较快的目的。

这种方式就构成了全文检索的基本思路。这部分从非结构化数据中提取出的然后重新组织的信息,我们称之 索引

还以读报纸为例,我们想关注最近英雄联盟 S8 全球总决赛的新闻,假如都是 RNG 的粉丝,如何快速找到 RNG 新闻的报纸和版块呢?

全文搜索的方式: 将所有报纸中所有版块中关键字进行提取,如"EDG","RNG","FW","战队","英雄联盟"等。然后对这些关键字建立索引,通过索引我们就可以对应到该关键词出现的报纸和版块。

为什么要用全文搜索引擎

那第二个问题来了, 为什么要用搜索引擎?

我们的所有数据在数据库里面都有,而且 Oracle、SQL Server 等数据库里也能提供查询检索或者聚类分析功能,直接通过数据库查询不就可以了吗?

确实,我们大部分的查询功能都可以通过数据库查询获得,如果查询效率低下,还可以通过建数据库索引,优化 SQL 等方式进行提升效率,甚至通过引入缓存来加快数据的返回速度。如果数据量更大,就可以分库分表来分担查询压力。

那为什么还要全文搜索引擎呢?我们主要从以下几个原因分析:

  • 数据类型
    全文索引搜索支持非结构化数据的搜索,可以更好地快速搜索大量存在的任何单词或单词组的非结构化文本。

    例如 Google,百度类的网站搜索,它们都是根据网页中的关键字生成索引,我们在搜索的时候输入关键字,它们会将该关键字即索引匹配到的所有网页返回

    还有常见的项目中应用日志的搜索等等。对于这些非结构化的数据文本,关系型数据库搜索不是能很好的支持。

  • 索引的维护
    一般传统数据库,全文检索都实现的很鸡肋,因为一般也没人用数据库存文本字段。

    进行全文检索需要扫描整个表,如果数据量大的话即使对SQL的语法优化,也收效甚微。建立了索引,但是维护起来也很麻烦,对于 insert 和 update 操作都会重新构建索引。

第三个问题: 什么时候使用全文搜索引擎?

  1. 搜索的数据对象是大量的非结构化的文本数据。

  2. 文件记录量达到数十万或数百万个甚至更多。

  3. 支持大量基于交互式文本的查询。

  4. 需求非常灵活的全文搜索查询。

  5. 对高度相关的搜索结果的有特殊需求,但是没有可用的关系数据库可以满足。

  6. 对不同记录类型、非文本数据操作或安全事务处理的需求相对较少的情况。

Lucene or Solr or ElasticSearch ?

现在主流的搜索引擎大概就是:Lucene,Solr,ElasticSearch。

每一个 Java 工程师都应该掌握的全文搜索引擎!

它们的索引建立都是根据 倒排索引 的方式生成索引, 何谓倒排索引?

还是先看看维基百科的解释:

维基百科
倒排索引(英语:Inverted index),也常被称为反向索引、置入档案或反向档案,是一种索引方法,被用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射。它是文档检索系统中最常用的数据结构。

接下来我们就来看看,这 3 种主流的使用倒排索引的全文搜索引擎。

Lucene

Lucene是一个Java全文搜索引擎,完全用Java编写。Lucene不是一个完整的应用程序,而是一个代码库和API,可以很容易地用于向应用程序添加搜索功能。

Lucene通过简单的API提供强大的功能:

可扩展的高性能索引

  • 在现代硬件上超过150GB /小时

  • 小RAM要求 - 只有1MB堆

  • 增量索引与批量索引一样快

  • 索引大小约为索引文本大小的20-30%

强大,准确,高效的搜索算法

  • 排名搜索 - 首先返回最佳结果

  • 许多强大的查询类型:短语查询,通配符查询,邻近查询,范围查询等

  • 现场搜索(例如标题,作者,内容)

  • 按任何字段排序

  • 使用合并结果进行多索引搜索

  • 允许同时更新和搜索

  • 灵活的分面,突出显示,连接和结果分组

  • 快速,内存效率和错误容忍的建议

  • 可插拔排名模型,包括矢量空间模型和Okapi BM25

  • 可配置存储引擎(编解码器)

跨平台解决方案

  • 作为Apache许可下的开源软件提供 ,允许您在商业和开源程序中使用Lucene

  • 100%-pure Java

  • 可用的其他编程语言中的实现是索引兼容的

但是Lucene只是一个框架,要充分利用它的功能,需要使用JAVA,并且在程序中集成Lucene。需要很多的学习了解,才能明白它是如何运行的,熟练运用Lucene确实非常复杂。

Solr

Apache Solr是一个基于名为Lucene的Java库构建的开源搜索平台。它以用户友好的方式提供Apache Lucene的搜索功能。

它提供分布式索引,复制,负载平衡查询以及自动故障转移和恢复。如果它被正确部署然后管理得好,它就能够成为一个高度可靠,可扩展且容错的搜索引擎。

很多互联网巨头,如Netflix,eBay,Instagram和亚马逊(CloudSearch)都使用Solr,因为它能够索引和搜索多个站点。

主要功能列表包括:

  • 全文搜索

  • 分页搜索

  • 实时索引

  • 动态群集

  • 数据库集成

  • NoSQL功能和丰富的文档处理(例如Word和PDF文件)

ElasticSearch

Elasticsearch是一个开源的基于Apache Lucene库构建的 RESTful 搜索引擎, 在Solr之后几年推出的。

它提供了一个分布式,多租户能力的全文搜索引擎,具有HTTP Web界面(REST)和无架构JSON文档。

Elasticsearch的官方客户端库提供Java,Groovy,PHP,Ruby,Perl,Python,.NET和Javascript。

分布式搜索引擎包括可以划分为分片的索引,并且每个分片可以具有多个副本。每个Elasticsearch节点都可以有一个或多个分片,其引擎也可以充当协调器,将操作委派给正确的分片。

Elasticsearch可通过近实时搜索进行扩展。其主要功能之一是多租户。 主要功能列表包括:

  • 分布式搜索

  • 多租户

  • 分析搜索

  • 分组和聚合

Elasticsearch vs. Solr,如何选择?

由于Lucene的复杂性,一般很少会考虑它作为搜索的第一选择,排除一些公司需要自研搜索框架,底层需要依赖Lucene。所以这里我们重点分析 Elasticsearch 和 Solr。

Elasticsearch vs. Solr。哪一个更好?他们有什么不同?你应该使用哪一个?

每一个Java工程师都应该掌握的全文搜索引擎!

历史比较

Apache Solr是一个成熟的项目,拥有庞大而活跃的开发和用户社区,以及Apache品牌。Solr于2006年首次发布到开源,长期以来一直占据着搜索引擎领域,并且是任何需要搜索功能的人的首选引擎。

它的成熟转化为丰富的功能,而不仅仅是简单的文本索引和搜索; 如分面,分组,强大的过滤,可插入的文档处理,可插入的搜索链组件,语言检测等。

Solr 在搜索领域占据了多年的主导地位。然后,在2010年左右,Elasticsearch成为市场上的另一种选择。那时候,它远没有Solr那么稳定,没有Solr的功能深度,没有思想分享,品牌等等。

Elasticsearch虽然很年轻,但它也自己的一些优势,Elasticsearch 建立在更现代的原则上,针对更现代的用例,并且是为了更容易处理大型索引和高查询率而构建的。

此外,由于它太年轻,没有社区可以合作,它可以自由地向前推进,而不需要与其他人(用户或开发人员)达成任何共识或合作,向后兼容,或任何其他更成熟的软件通常必须处理。

因此,它在Solr之前就公开了一些非常受欢迎的功能(例如,接近实时搜索,英文:Near Real-Time Search)。

从技术上讲,NRT搜索的能力确实来自Lucene,它是 Solr 和 Elasticsearch 使用的基础搜索库。

具有讽刺意味的是,因为 Elasticsearch 首先公开了NRT搜索,所以人们将NRT搜索与Elasticsearch 联系在一起,尽管 Solr 和 Lucene 都是同一个 Apache 项目的一部分,因此,人们会首先期望 Solr 具有如此高要求的功能。

特征差异比较

这两个搜索引擎都是流行的,先进的的开源搜索引擎。它们都是围绕核心底层搜索库 - Lucene构建的

但它们又是不同的。像所有东西一样,每个都有其优点和缺点,根据您的需求和期望,每个都可能更好或更差。

所以,话不多说,先来看下它们的差异清单:

每一个Java工程师都应该掌握的全文搜索引擎!

综合比较

另外,我们在从以下几个方面来分析下:

  • 近几年的流行趋势 我们查看一下这两种产品的Google搜索趋势。谷歌趋势表明,与 Solr 相比,Elasticsearch具有很大的吸引力,但这并不意味着Apache Solr已经死亡

    虽然有些人可能不这么认为,但Solr仍然是最受欢迎的搜索引擎之一,拥有强大的社区和开源支持。看下图两者的对比:

每一个Java工程师都应该掌握的全文搜索引擎!

  • 安装和配置 与Solr相比,Elasticsearch易于安装且非常轻巧。此外,您可以在几分钟内安装并运行Elasticsearch。

    但是,如果Elasticsearch管理不当,这种易于部署和使用可能会成为一个问题。基于JSON的配置很简单,但如果要为文件中的每个配置指定注释,那么它不适合您。

    总的来说,如果您的应用使用的是JSON,那么Elasticsearch是一个更好的选择。否则,请使用Solr,因为它的schema.xml和solrconfig.xml都有很好的文档记录。

  • 社区 Solr拥有更大的开发者和贡献者社区,ES的社区规模较小,但活跃度高,用户也在不断增长。

    Solr是真正的开源社区代码,任何人都可以为Solr做出贡献,并且根据优点选出新的Solr开发人员(也称为提交者)。

    Elasticsearch在技术上是开源的,但在精神上却不那么重要。任何人都可以看到来源,任何人都可以更改它并提供贡献,但只有Elasticsearch的员工才能真正对Elasticsearch进行更改。

    Solr贡献者和提交者来自许多不同的组织,而Elasticsearch提交者来自单个公司。

  • 成熟度 Solr更成熟,但ES增长迅速,我认为它稳定。

  • 文档 Solr在这里得分很高。它是一个非常有据可查的产品,具有清晰的示例和API用例场景。

    Elasticsearch的文档组织良好,但它缺乏好的示例和清晰的配置说明。

总结

那么问题来了, 到底是 Solr 还是 Elasticsearch?

这个很难找到明确的答案,无论您选择Solr还是Elasticsearch,首先需要了解正确的用例和未来需求。总结他们的每个属性。 记住:

  • 由于易于使用,Elasticsearch在新开发者中更受欢迎。但是,如果您已经习惯了与Solr合作,请继续使用它,因为迁移到Elasticsearch没有特定的优势。

  • 如果除了搜索文本之外还需要它来处理分析查询,Elasticsearch是更好的选择。

  • 如果需要分布式索引,则需要选择Elasticsearch。对于需要良好可伸缩性和性能的云和分布式环境,Elasticsearch是更好的选择。

  • 两者都有良好的商业支持(咨询,生产支持,整合等)

  • 两者都有很好的操作工具,尽管Elasticsearch因其易于使用的API而更多地吸引了DevOps人群,因此可以围绕它创建一个更加生动的 工具 生态系统。

  • Elasticsearch在开源日志管理用例中占据主导地位,许多组织在Elasticsearch中索引它们的日志以使其可搜索。虽然Solr现在也可以用于此目的,但它只是错过了这一想法。

  • Solr仍然更加面向文本搜索。另一方面,Elasticsearch 通常用于过滤和分组 - 分析查询工作负载 - 而不一定是文本搜索。

    Elasticsearch 开发人员在 Lucene 和 Elasticsearch 级别上投入了大量精力使此类查询更高效(降低内存占用和CPU使用)。

    因此,对于不仅需要进行文本搜索,而且需要复杂的搜索时间聚合的应用程序,Elasticsearch是一个更好的选择。

  • Elasticsearch更容易上手,一个下载和一个命令就可以启动一切。Solr传统上需要更多的工作和知识,但Solr最近在消除这一点上取得了巨大的进步,现在只需努力改变它的声誉。

  • 在性能方面,它们大致相同。我说“大致”,因为没有人做过全面和无偏见的基准测试。

    对于95%的用例,任何一种选择在性能方面都会很好,剩下的5%需要用它们的特定数据和特定的访问模式来测试这两种解决方案。

  • 从操作上讲,Elasticsearch使用起来比较简单 - 它只有一个进程。Solr在其类似Elasticsearch的完全分布式部署模式SolrCloud中依赖于Apache ZooKeeper。

    ZooKeeper是超级成熟,超级广泛使用等等,但它仍然是另一个活跃的部分。

    也就是说,如果您使用的是Hadoop,HBase,Spark,Kafka或其他一些较新的分布式软件,您可能已经在组织的某个地方运行ZooKeeper。

  • 虽然Elasticsearch内置了类似ZooKeeper的组件Xen,但ZooKeeper可以更好地防止有时在Elasticsearch集群中出现的可怕的裂脑问题。

    公平地说,Elasticsearch开发人员已经意识到这个问题,并致力于改进Elasticsearch的这个方面。

  • 如果您喜欢监控和指标,那么使用Elasticsearch,您将会进入天堂 。这个东西比新年前夜在时代广场可以挤压的人有更多的指标!Solr暴露了关键指标,但远不及Elasticsearch那么多。

总之,两者都是功能丰富的搜索引擎,只要设计和实现得当,它们或多或少都能提供相同的性能。本篇文章的总体内容大致如下图,该图由园友ReyCG精心绘制并提供。

每一个Java工程师都应该掌握的全文搜索引擎!

参考:

  1. https://www.datanami.com/2015/01/22/solr-elasticsearch-question/

  2. https://blog.csdn.net/hhx0626/article/details/78095593/

  3. https://www.elastic.co/cn/

  4. https://logz.io/blog/solr-vs-elasticsearch/

  5. https://sematext.com/blog/solr-vs-elasticsearch-differences/

End

作者: JaJian

来源:

https://www.cnblogs.com/jajian/p/9801154.html

本文版权归作者所有

为您推荐

  1. 如何设计一个百万级用户的抽奖系统?

  2. 阿里二面:设计一个电商平台积分兑换系统!

  3. 扎心一问!你凭什么成为top1%的Java工程师?

  4. 【干货走一波】千万级用户的大型网站,应该如何设计其高并发架构?

  5. PK光明顶?江湖上流传的几大消息队列门派,到底有什么本质区别?

  6. 扒一扒 JVM 的垃圾回收机制,拿大厂offer少不了它!

  7. 面试阿里?如果对别人开源的Rocket MQ了如指掌,岂不是很加分?

  8. 百度、腾讯热门面试题:聊聊Unix与Java的IO模型?(含详细解析)

  9. 35岁的大龄 码农 们,如何才能不被社会淘汰掉?

  10. 一步一图,带你走进Netty的世界!

  11. 想要去阿里面试?你必须得跨过JVM这道坎!

  12. 你连Nginx怎么转发给你请求都说不清楚,还好意思说自己不是CRUD工程师?

长按下图二维码,即刻关注【 狸猫技术窝

阿里、京东、美团、字节跳动

顶尖技术专家 坐镇

为IT人打造一个 “有温度” 的技术窝!

每一个Java工程师都应该掌握的全文搜索引擎!


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 我们


推荐阅读
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
  • CentOS 7部署KVM虚拟化环境之一架构介绍
    本文介绍了CentOS 7部署KVM虚拟化环境的架构,详细解释了虚拟化技术的概念和原理,包括全虚拟化和半虚拟化。同时介绍了虚拟机的概念和虚拟化软件的作用。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • 本文介绍了Redis中RDB文件和AOF文件的保存和还原机制。RDB文件用于保存和还原Redis服务器所有数据库中的键值对数据,SAVE命令和BGSAVE命令分别用于阻塞服务器和由子进程执行保存操作。同时执行SAVE命令和BGSAVE命令,以及同时执行两个BGSAVE命令都会产生竞争条件。服务器会保存所有用save选项设置的保存条件,当满足任意一个保存条件时,服务器会自动执行BGSAVE命令。此外,还介绍了RDB文件和AOF文件在操作方面的冲突以及同时执行大量磁盘写入操作的不良影响。 ... [详细]
  • 本文是一位90后程序员分享的职业发展经验,从年薪3w到30w的薪资增长过程。文章回顾了自己的青春时光,包括与朋友一起玩DOTA的回忆,并附上了一段纪念DOTA青春的视频链接。作者还提到了一些与程序员相关的名词和团队,如Pis、蛛丝马迹、B神、LGD、EHOME等。通过分享自己的经验,作者希望能够给其他程序员提供一些职业发展的思路和启示。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • Oracle Database 10g许可授予信息及高级功能详解
    本文介绍了Oracle Database 10g许可授予信息及其中的高级功能,包括数据库优化数据包、SQL访问指导、SQL优化指导、SQL优化集和重组对象。同时提供了详细说明,指导用户在Oracle Database 10g中如何使用这些功能。 ... [详细]
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • 本文介绍了在Oracle数据库中创建序列时如何选择cache或nocache参数。cache参数可以提高序列的存取速度,但可能会导致序列丢失;nocache参数可以避免序列丢失,但在高并发访问时可能导致性能问题。文章详细解释了两者的区别和使用场景。 ... [详细]
  • Windows7 64位系统安装PLSQL Developer的步骤和注意事项
    本文介绍了在Windows7 64位系统上安装PLSQL Developer的步骤和注意事项。首先下载并安装PLSQL Developer,注意不要安装在默认目录下。然后下载Windows 32位的oracle instant client,并解压到指定路径。最后,按照自己的喜好对解压后的文件进行命名和压缩。 ... [详细]
author-avatar
哥晕死_476
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有