阜新门户网站建设某旅行社网站建设论文
web/
2025/9/29 9:42:51/
文章来源:
阜新门户网站建设,某旅行社网站建设论文,漫画网站源码,免费网络电话试用ElasticSearch
Elasticsearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎#xff0c;基于RESTful web接口。Elasticsearch是用Java语言开发的#xff0c;并作为Apache许可条款下的开放源码发布#xff0c;是一种流行的企业级搜索引擎。Elas…ElasticSearch
Elasticsearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎基于RESTful web接口。Elasticsearch是用Java语言开发的并作为Apache许可条款下的开放源码发布是一种流行的企业级搜索引擎。Elasticsearch用于云计算中能够达到实时搜索稳定可靠快速安装使用方便。官方客户端在Java、.NETC#、PHP、Python、Apache Groovy、Ruby和许多其他语言中都是可用的。根据DB-Engines的排名显示Elasticsearch是最受欢迎的企业搜索引擎其次是Apache Solr也是基于Lucene
如京东淘宝
Lucene是一个Java语言的搜索引擎类库,是Apache公司的顶级项目由DougCutting于1999年研发。官网地址: https:// lucene.apache.org/
重要性
分布式的实时文件存储每个字段都被索引并可被搜索实时分析的分布式搜索引擎可以扩展到上百台服务器处理PB级结构化或非结构化数据
倒排索引
倒排索引的概念是基于MySQL这样的正向索引而言的
正向索引 但如果是基于title做模糊查询只能是逐行扫描数据流程如下
用户搜索数据条件是title符合“%手机%”逐行获取数据比如id为1的数据判断数据中的title是否符合用户搜索条件如果符合则放入结果集不符合则丢弃。回到步骤1
逐行扫描也就是全表扫描随着数据量增加其查询效率也会越来越低。当数据量达到数百万时就是一场灾难。
倒排索引
倒排索引中有两个非常重要的概念
文档Document用来搜索的数据其中的每一条数据就是一个文档。例如一个网页、一个商品信息词条Term对文档数据或用户搜索数据利用某种算法分词得到的具备含义的词语就是词条。例如我是中国人就可以分为我、是、中国人、中国、国人这样的几个词条
创建倒排索引是对正向索引的一种特殊处理流程如下
将每一个文档的数据利用算法分词得到一个个词条创建表每行数据包括词条、词条所在文档id、位置等信息因为词条唯一性可以给词条创建索引例如hash表结构索引 倒排索引的搜索流程如下以搜寻“华为手机”为例
用户输入条件 “华为手机” 进行搜索。对用户输入内容分词得到词条 华为 、 手机 。拿着词条在倒排索引中查找可以得到包含词条的文档id1、2、3。拿着文档id到正向索引中查找具体文档 虽然要先查询倒排索引再查询倒排索引但是无论是词条、还是文档id都建立了索引查询速度非常快无需全表扫描。
正向和倒排
正向索引是最传统的根据id索引的方式。但根据词条查询时必须先逐条获取每个文档然后判断文档中是否包含所需要的词条是根据文档找词条的过程。而倒排索引则相反是先找到用户要搜索的词条根据词条得到保护词条的文档的id然后根据id获取文档。是根据词条找文档的过程
正向索引
优点
可以给多个字段创建索引根据索引字段搜索、排序速度非常快
缺点
根据非索引字段或者索引字段中的部分词条查找时只能全表扫描
倒排索引
优点
根据词条搜索、模糊搜索时速度非常快
缺点
只能给词条创建索引而不是字段无法根据字段做排序
ES的一些概念
elasticsearch中有很多独有的概念与mysql中略有差别但也有相似之处
文档和字段
elasticsearch是面向**文档Document**存储的可以是数据库中的一条商品数据一个订单信息。文档数据会被序列化为json格式后存储在elasticsearch中 而Json文档中往往包含很多的字段Field类似于数据库中的列
索引和映射
索引Index就是相同类型的文档的集合。
例如
所有用户文档就可以组织在一起称为用户的索引所有商品的文档可以组织在一起称为商品的索引所有订单的文档可以组织在一起称为订单的索引 因此我们可以把索引当做是数据库中的表。
数据库的表会有约束信息用来定义表的结构、字段的名称、类型等信息。因此索引库中就有映射(mapping是索引中文档的字段约束信息类似表的结构约束。
MySQL和ElasticSearch
我们统一的把mysql与elasticsearch的概念做一下对比 ES环境安装
ES环境需要ES和分词器
环境搭建步骤
windows版ES下载网址https://www.elastic.co/cn/downloads/elasticsearch下载分词器4IK分词器https://github.com/medcl/elasticsearch-analysis-ik/releases解压缩ES并且在解压缩的plugins创建ik文件夹将4IK分词器解压后的所有文件拷贝到创建的ik文件夹下
启动ES
找到ES文件夹下的bin文件夹双击文件 elasticsearch.bat弹出窗口不要关闭浏览器访问localhost:9200能看到json代表启动成功
4IK分词器
作用
创建倒排索引时对文档分词用户搜索时对输入的内容分词
IK分词器的模式
ik_smart智能切分粗粒度ik_max_word最细切分细粒度
索引库操作
索引库就类似数据库表mapping映射就类似表的结构。
我们要向es中存储数据必须先创建“库”和“表”。
mapping映射属性
mapping是对索引库中文档的约束常见的mapping属性包括
type字段数据类型常见的简单类型有
字符串text可分词的文本、keyword精确值例如品牌、国家、ip地址数值long、integer、short、byte、double、float布尔boolean日期date对象object
index是否创建索引默认为true
analyzer使用哪种分词器
properties该字段的子字段
Eg
{age: 18,weight: 70.2,isMarried: false,info: apesourceJavaEE王讲师,email: wangls163.com,score: [99.1, 99.5, 98.9],name: {firstName: 师傅,lastName: 王}
}对应的每个字段映射mapping
age类型为 integer参与搜索因此需要index为true无需分词器weight类型为float参与搜索因此需要index为true无需分词器isMarried类型为boolean参与搜索因此需要index为true无需分词器info类型为字符串需要分词因此是text参与搜索因此需要index为true分词器可以用ik_smartemail类型为字符串但是不需要分词因此是keyword不参与搜索因此需要index为false无需分词器score虽然是数组但是我们只看元素的类型类型为float参与搜索因此需要index为true无需分词器name类型为object需要定义多个子属性 name.firstName类型为字符串但是不需要分词因此是keyword参与搜索因此需要index为true无需分词器name.lastName类型为字符串但是不需要分词因此是keyword参与搜索因此需要index为true无需分词器
创建索引库和映射
基本语法
请求方式PUT请求路径/索引库名可以自定义请求参数mapping
格式
{mappings:{properties:{age:{type:integer},isMarried:{type:boolean},name:{type:text,analyzer:ik_smart},info:{type:text,index:false},pet:{properties:{dog:{type:text},cat:{type:text }}}}}
}Postman测试创建索引库和映射
查询索引库
基本语法
请求方式GET请求路径/索引库名请求参数无
格式
GET /索引库名egpostman发送GET请求localhost:9200/teachers
修改索引库
倒排索引结构虽然不复杂但是一旦数据结构改变比如改变了分词器就需要重新创建倒排索引这简直是灾难。因此索引库一旦创建无法修改mapping。
虽然无法修改mapping中已有的字段但是却允许添加新的字段到mapping中因为不会对倒排索引产生影响。
语法说明
PUT /索引库名/_mapping
{properties: {新字段名:{type: integer}}
}eg:postman发送PUT请求:localhost:9200/teachers/_mapping 删除索引库
语法
请求方式DELETE请求路径/索引库名请求参数无
格式
DELETE /索引库名postman发送DELETE请求localhost:9200/teachers
总结
创建索引库PUT /索引库名查询索引库GET /索引库名删除索引库DELETE /索引库名添加字段PUT /索引库名/_mapping
文档操作
新增文档
语法
POST /索引库名/_doc/文档id
{字段1: 值1,字段2: 值2,字段3: {子属性1: 值3,子属性2: 值4},// ...
}eg
POST请求localhost:9200/teachers/_doc/1
{info:java程序开发工程师,age:23,name:詹姆斯高斯林,pet:{拉布拉多:旺财,英短:小老弟}
}查询文档
根据rest风格新增是post查询应该是get不过查询一般都需要条件这里我们把文档id带上。
语法
GET /{索引库名称}/_doc/{id}查看数据
GET请求localhost:9200/teachers/_doc/1
localhost:9200/teachers/_doc/1删除文档
删除使用DELETE请求同样需要根据id进行删除
语法
DELETE /{索引库名}/_doc/id值eg
DELETE请求
localhost:9200/teachers/_doc/1修改文档
全量修改直接覆盖原来的文档增量修改修改文档中的部分字段
全量修改
全量修改是覆盖原来的文档其本质是
根据指定的id删除文档新增一个相同id的文档
**注意**如果根据id删除时id不存在第二步的新增也会执行也就从修改变成了新增操作了
语法
PUT /{索引库名}/_doc/文档id
{字段1: 值1,字段2: 值2,// ... 略
}eg
postman发送PUT请求localhost:9200/teachers/_doc/1
{info:python程序开发工程,name:吉多范罗苏姆,age:22,pet:{拉布拉多:旺财,英短:小老弟}
}全量修改
增量修改是只修改指定id匹配的文档中的部分字段
语法
POST /{索引库名}/_update/文档id
{doc: {字段名: 新的值,}
}eg
postman发送POST请求localhost:9200/teachers/_update/1
{doc:{name:詹姆斯高斯林再牛逼也进不了谷歌}
}总结
创建文档POST /{索引库名}/_doc/文档id { json文档 }查询文档GET /{索引库名}/_doc/文档id删除文档DELETE /{索引库名}/_doc/文档id修改文档 全量修改PUT /{索引库名}/_doc/文档id { json文档 }增量修改POST /{索引库名}/_update/文档id { “doc”: {字段}}
RestAPI
ES官方提供了各种不同语言的客户端用来操作ES。这些客户端的本质就是组装DSL语句通过http请求发送给ES。官方文档地址https://www.elastic.co/guide/en/elasticsearch/client/index.html
其中的Java Rest Client又包括两种
Java Low Level Rest ClientJava High Level Rest Client
主要介绍Java High Level Rest Client
数据库建表语句
CREATE TABLE tb_hotel (id bigint(20) NOT NULL COMMENT 酒店id,name varchar(255) NOT NULL COMMENT 酒店名称例7天酒店,address varchar(255) NOT NULL COMMENT 酒店地址例航头路,price int(10) NOT NULL COMMENT 酒店价格例329,score int(2) NOT NULL COMMENT 酒店评分例45就是4.5分,brand varchar(32) NOT NULL COMMENT 酒店品牌例如家,city varchar(32) NOT NULL COMMENT 所在城市例上海,star_name varchar(16) DEFAULT NULL COMMENT 酒店星级从低到高分别是1星到5星1钻到5钻,business varchar(255) DEFAULT NULL COMMENT 商圈例虹桥,latitude varchar(32) NOT NULL COMMENT 纬度例31.2497,longitude varchar(32) NOT NULL COMMENT 经度例120.3925,pic varchar(255) DEFAULT NULL COMMENT 酒店图片例:/img/1.jpg,PRIMARY KEY (id)
) ENGINEInnoDB DEFAULT CHARSETutf8mb4;mapping映射分析
酒店数据的索引库结构
{mappings: {properties: {id: {type: keyword},name:{type: text,analyzer: ik_max_word,copy_to: all},address:{type: keyword,index: false,copy_to: all},price:{type: integer},score:{type: integer},brand:{type: keyword,copy_to: all},city:{type: keyword,copy_to: all},starName:{type: keyword},business:{type: keyword},location:{type: geo_point},pic:{type: keyword,index: false},all:{type: text,analyzer: ik_max_word}}}
}几个特殊字段说明:
location地理坐标里面包含精度、纬度
all一个组合字段其目的是将多字段的值 利用copy_to合并提供给用户搜索
地理坐标说明: copy_to说明: JAVA中使用ES
初始化RestClient
在elasticsearch提供的API中与elasticsearch一切交互都封装在一个名为RestHighLevelClient的类中必须先完成这个对象的初始化建立与elasticsearch的连接。
在Spring Boot中使用ES三步骤 引入es的RestHighLevelClient依赖 dependencygroupIdorg.elasticsearch.client/groupIdartifactIdelasticsearch-rest-high-level-client/artifactId
/dependency因为SpringBoot默认的ES版本是7.6.2所以我们需要覆盖默认的ES版本 propertiesjava.version1.8/java.versionelasticsearch.version7.12.0/elasticsearch.version
/properties初始化RestHighLevelClient 将RestHighLevelClient注入容器可以写配置类也可以写在启动类中 Bean
public RestHighLevelClient restHighLevelClient(){RestHighLevelClient client new RestHighLevelClient(RestClient.builder(HttpHost.create(http://localhost:9200)));
}创建索引库 准备索引库映射字符串 public class HotelConstants {public static final String MAPPING_TEMPLATE {\n \mappings\: {\n \properties\: {\n \id\: {\n \type\: \keyword\\n },\n \name\:{\n \type\: \text\,\n \analyzer\: \ik_max_word\,\n \copy_to\: \all\\n },\n \address\:{\n \type\: \keyword\,\n \index\: false\n },\n \price\:{\n \type\: \integer\\n },\n \score\:{\n \type\: \integer\\n },\n \brand\:{\n \type\: \keyword\,\n \copy_to\: \all\\n },\n \city\:{\n \type\: \keyword\,\n \copy_to\: \all\\n },\n \starName\:{\n \type\: \keyword\\n },\n \business\:{\n \type\: \keyword\\n },\n \location\:{\n \type\: \geo_point\\n },\n \pic\:{\n \type\: \keyword\,\n \index\: false\n },\n \all\:{\n \type\: \text\,\n \analyzer\: \ik_max_word\\n }\n }\n }\n };
}索引库的操作 SpringBootTest
class SpringbootEs01ApplicationTests {private RestHighLevelClient client;BeforeEachvoid setUp(){this.client new RestHighLevelClient(RestClient.builder(HttpHost.create(http://localhost:9200)));}AfterEachvoid tearDown() throws Exception{this.client.close();}// 判断索引库是否存在Testvoid testExistsHotelIndex() throws Exception {GetIndexRequest request new GetIndexRequest(hotels);boolean exists client.indices().exists(request, RequestOptions.DEFAULT);System.err.println(exists ? 索引库已经存在:索引库不存在);}// 创建索引库Testvoid createHotelIndex() throws Exception{// 创建Request对象CreateIndexRequest request new CreateIndexRequest(hotels);// 准备请求的参数DSL语句request.source(HotelConstants.MAPPING_TEMPLATE, XContentType.JSON);// 发送请求client.indices().create(request,RequestOptions.DEFAULT);}// 删除索引库Testvoid delteHotelIndex() throws Exception{// 创建Request对象DeleteIndexRequest request new DeleteIndexRequest(hotels);// 发送请求client.indices().delete(request,RequestOptions.DEFAULT);}}总结
JavaRestClient操作elasticsearch的流程基本类似。核心是client.indices()方法来获取索引库的操作对象
索引库操作的基本步骤
初始化RestHighLevelClient创建XxxIndexRequest。XXX是Create、Get、Delete准备DSL Create时需要其它是无参发送请求。调用RestHighLevelClient#indices().xxx()方法xxx是create、exists、delete
文档操作
演示在juint单元测试中进行准备
SpringBootTest
public class HotelDocumentTests {// 核心对象private RestHighLevelClient client;// 需要从数据库中查数据存入es装配业务Autowired(required false)private IHotelService service;BeforeEachvoid setUp(){this.client new RestHighLevelClient(RestClient.builder(HttpHost.create(http://localhost:9200)));}AfterEachvoid tearDown() throws Exception{this.client.close();}
}从数据库中新增一条数据到ES Test
void addDocument() throws Exception{// 从数据库查询一条数据Hotel hotel service.getById(395434);System.out.println(hotel);// 转换为文档类型HotelDoc hotelDoc new HotelDoc(hotel);// 将文档类型转为JSON格式String json JSON.toJSONString(hotelDoc);// 准备request请求对象IndexRequest request new IndexRequest(hotels).id(hotelDoc.getId().toString());// 准备JSON文档request.source(json, XContentType.JSON);// 发送请求client.index(request, RequestOptions.DEFAULT);
}从ES中删除一条数据 Test
void deleteDocument() throws Exception{// 准备删除请求RequestDeleteRequest request new DeleteRequest(hotels, 395434);client.delete(request,RequestOptions.DEFAULT);
}修改ES中的数据 修改有两种方式 全量修改本质是先根据id删除再新增增量修改修改文档中的指定字段值在RestClient的API中全量修改与新增的API完全一致 Test
void updateDocument() throws Exception{// 准备修改请求UpdateRequestUpdateRequest request new UpdateRequest(hotels, 395434);// 准备请求参数要修改的数据内容request.doc(name,W酒店,city,西安,price,2000,starName,五星级);
}批量新增数据到ES中 Test
void addAllDocument() throws Exception{// 数据库全查ListHotel hotels service.list();// 准备请求BulkRequest bulkRequest new BulkRequest();// 准备参数for(Hotel hotel : hotels){// 类型转化HotelDoc hotelDoc new HotelDoc(hotel);// 请求添加数据bulkRequest.add(new IndexRequest(hotels).id(hotelDoc.getId().toString()).source(JSON.toJSONString(hotelDoc),XContentType.JSON));}// 发送请求client.bulk(bulkRequest,RequestOptions.DEFAULT);
}总结
文档操作的基本步骤
初始化RestHighLevelClient创建XxxRequest。XXX是Index、Get、Update、Delete、Bulk准备参数Index、Update、Bulk时需要发送请求。调用RestHighLevelClient#.xxx()方法xxx是index、get、update、delete、bulk解析结果Get时需要
查询文档操作
Elasticsearch提供了基于JSON的DSLDomain Specific Language来定义查询。常见的查询类型包括
查询所有查询出所有数据一般测试用(不会显示出所有自带分页功能)。例如match_all
全文检索full text查询利用分词器对用户输入内容分词然后去倒排索引库中匹配。例如
match_query单字段查询multi_match_query多字段查询任意一个字段符合条件就算符合查询条件
准确查询根据精确词条值查找数据一般是查找keyword、数值、日期、boolean等类型字段。例如
idsid查询range根据值的范围查询term根据词条精确值查询
地理geo查询根据经纬度查询。例如
geo_distancegeo_bounding_box
复合compound查询复合查询可以将上述各种查询条件组合起来合并查询条件。例如 bool function_score 查询一条数据 Test
void getDocumentById() throws Exception{// 准备查询请求GetRequestGetRequest getRequest new GetRequest(hotels, 395434);// 发送请求得到响应GetResponse response client.get(getRequest, RequestOptions.DEFAULT);// 解析响应结果String json response.getSourceAsString();HotelDoc hotelDoc JSON.parseObject(json,HotelDoc.class);System.out.println(hotelDoc);
}解析对象方法 // 解析对象方法
public void show(SearchResponse response){// 解析响应SearchHits searchHits response.getHits();long total searchHits.getTotalHits().value;System.out.println(总计查询数据total条);SearchHit[] hits searchHits.getHits();for(SearchHit hit :hits){/// 获取文档sourceString json hit.getSourceAsString();// 反序列化HotelDoc hotelDoc JSON.parseObject(json, HotelDoc.class);System.out.println(hotelDochotelDoc);}
}全查 Test
void findAllDocument() throws IOException{// 准备requestSearchRequest request new SearchRequest(hotels);// 2.准备DSLQueryBuilders构造查询条件request.source().query(QueryBuilders.matchAllQuery());// 3.发送请求SearchResponse response client.search(request, RequestOptions.DEFAULT);show(response);
}全文索引----查询all字段内容中含有如家的 Test
void testMacth() throws IOException{// 准备请求SearchRequest request new SearchRequest(hotels);// 准备DSLrequest.source().query(QueryBuilders.matchQuery(all,如家));// 发送请求SearchResponse response client.search(request, RequestOptions.DEFAULT);show(response);
}全文索引----多字段查询 Test
void testMultiMatchQuery()throws IOException {// 准备请求SearchRequest request new SearchRequest(hotels);// 准备DSLrequest.source().query(QueryBuilders.multiMatchQuery(上海,name,city));// 发送请求SearchResponse response client.search(request, RequestOptions.DEFAULT);show(response);
}精确查询1 // term:根据词条精准查询字段等值查询
Test
void testTerm() throws IOException{// 准备请求SearchRequest request new SearchRequest(hotels);// 准备DSLrequest.source().query(QueryBuilders.termQuery(brand,希尔顿));// 发送请求SearchResponse response client.search(request, RequestOptions.DEFAULT);show(response);
}精确查询2 // range范围查询
Test
void testRange() throws IOException {// 准备请求SearchRequest request new SearchRequest(hotels);// 准备DSLrequest.source().query(QueryBuilders.rangeQuery(price).gte(200).lte(300));// 发送请求SearchResponse response client.search(request, RequestOptions.DEFAULT);show(response);
}精确查询3 // ids查询
Test
void testIds() throws IOException {// 准备请求SearchRequest request new SearchRequest(hotels);// 准备DSLrequest.source().query(QueryBuilders.idsQuery().addIds(395434,3532));// 发送请求SearchResponse response client.search(request, RequestOptions.DEFAULT);show(response);
}复合查询 // bool复合查询
Test
void testBool() throws IOException{// 准备请求SearchRequest request new SearchRequest(hotels);// 准备条件/*-- 方式1 ----*/// BoolQueryBuilder boolQueryBuilder QueryBuilders.boolQuery();// boolQueryBuilder.must(QueryBuilders.termQuery(city,北京));// boolQueryBuilder.filter(QueryBuilders.rangeQuery(price).lte(500));// // 准备DSL// request.source().query(boolQueryBuilder);/*---- 方式2 ----*/request.source().query(QueryBuilders.boolQuery().must(QueryBuilders.termQuery(city,北京)).filter(QueryBuilders.rangeQuery(price).lte(500)));// 发送请求SearchResponse response client.search(request, RequestOptions.DEFAULT);show(response);
}自定义分页规则 // 自定义分页方式
Test
void testPageAndSort() throws IOException{int page 1; //页码int size 5; //步长String searchName希尔顿; // 查询条件// 准备请求SearchRequest request new SearchRequest(hotels);if (searchName null){request.source().query(QueryBuilders.matchAllQuery());}else {request.source().query(QueryBuilders.matchQuery(brand,searchName));}// 自定义分页request.source().from((page-1)*size).size(size);// 自定义排序request.source().sort(price, SortOrder.DESC);SearchResponse response client.search(request, RequestOptions.DEFAULT);show(response);
}总结
SpringBoot中整合ES的实现步骤 导pom文件ES的坐标 propertiesjava.version1.8/java.versionelasticsearch.version7.12.0/elasticsearch.version
/properties写ES配置类 Configuration
public class ElasticSearchConfig {Beanpublic RestHighLevelClient restHighLevelClient(){return new RestHighLevelClient(RestClient.builder(HttpHost.create(http://localhost:9200)));}
}写ES映射Mapping 建立ES索引库 public void createEs() throws IOException {GetIndexRequest request new GetIndexRequest(employee);// 判断索引库是否存在boolean exists restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);// 如果不存在建库if(!exists){// 创建Request对象CreateIndexRequest createIndexRequest new CreateIndexRequest(employee);// 准备请求的参数DSL语句createIndexRequest.source(EmployeeConstants.MAPPING_TEMPLATE, XContentType.JSON);// 发送请求restHighLevelClient.indices().create(createIndexRequest,RequestOptions.DEFAULT);}
}把数据库中的数据添加到ES中 public void addAllEmployee() throws Exception{// 数据库全查ListEmployee list employeeService.list();// 准备请求BulkRequest bulkRequest new BulkRequest();for(Employee e : list){bulkRequest.add(new IndexRequest(employee).id(e.getId().toString()).source(JSON.toJSONString(e),XContentType.JSON));}// 发送请求restHighLevelClient.bulk(bulkRequest,RequestOptions.DEFAULT);
}业务中查询ES修改添加删除数据库同步ES 写解析 // 解析对象方法
public void show(SearchResponse response){// 解析响应SearchHits searchHits response.getHits();long total searchHits.getTotalHits().value;System.out.println(总计查询数据total条);SearchHit[] hits searchHits.getHits();for(SearchHit hit :hits){/// 获取文档sourceString json hit.getSourceAsString();// 反序列化HotelDoc hotelDoc JSON.parseObject(json, HotelDoc.class);System.out.println(hotelDochotelDoc);}
}注意操作ES需要装配核心对象RestHighLevelClient
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/83825.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!