深度学习在同城租房搜索排序的应用
导读:深度学习得益于良好的深层特征表达性,目前在视觉、文本、语音等领域获得了广泛的应用。搜索领域紧贴用户需求,作为深度学习商业变现最成功的路径之一,众多头部企业发展出了许多优秀的应用。58同城是国内最大的生活信息服务平台,涵盖房产、招聘、黄页、二手车等多个业务,在多个业务线的搜索服务上,TEG搜索排序部持续对外提供稳定的排序能力。
应用背景
本文聚焦租房业务线,围绕数据、模型,对搜索排序应用深度学习提升连接效率的经验做阐释。
58APP端用户的一个典型使用场景如图1所示。用户通过搜索某一具体小区名或点选某一具体地铁站,发起一次搜索请求,服务端检索到一批相关帖子后,采用某种策略区分帖子的展现位置,最终返回给用户排序后的帖子列表。
图1 用户典型使用场景
用户指定一个搜索场景后,返回哪些信息给用户,信息如何排序,从根本上说是怎样更好地完成信息与用户需求的匹配,即是否匹配了用户的搜索意图。对于更商业化的现实意义而言,更好的排序不仅能够提升用户的检索效率,提高用户粘性,改善用户获取的信息质量,针对具体业务线还能够提高用户点击或转化的几率,增加平台的收入。
用于信息排序的模型,核心能力是处理多样性的特征数据,挖掘用户和候选贴的关联关系,合理的建模用户兴趣。深度学习模型拥有在大规模帖子信息中稳健的处理能力,能够提取深层次的帖子、用户信息,拟合真实的用户兴趣,在业界的排序应用中效果显著。
本文主要对应用深度学习模型排序中的点击率、转化率预估技术做介绍。
排序架构简述
搜索排序的核心架构如图2所示,整体可以分为数据层和策略层。数据层主要提供排序模型所需的特征数据,策略层提供具体的排序能力。
数据层从前后端日志拿到埋点数据,整合业务侧提供的帖子、用户等数据,得到基础信息日志,通过数据分析,分组提取日志中的特征,部分特征刷入特征中心,供线上使用。离线通过正负采样和特征处理得到模型需要的训练样本。
策略层包含模型和业务策略两部分,模型部分是运用机器学习或深度学习模型,学习隐含信息,提供初步的排序信息,业务策略针对具体的业务线需求,在模型排序基础上添加分层或调权能力,获得更稳健的排序结果。
图2 搜索排序核心架构
模型迭代路径
排序模型的核心能力是处理多样性的特征数据,挖掘用户和候选贴间的关联关系,判断用户的兴趣点。在传统的排序策略中,最简单的方案是按照帖子更新时间排序,提供给用户最新信息,这种方案忽略了用户本身兴趣。后续考虑到具体的业务场景差异,加上人为的条件约束来排序,虽然策略日趋复杂,但核心排序能力依然是主观的,不具有普适性。接着引入了机器学习模型,如LR、FM、Xgboost等,逐步增加不同特征的交叉信息,排序性能更加可靠,对于海量的帖子库拥有了一定的用户兴趣匹配能力,但传统机器学习方法极度依赖输入特征数据的前期处理,即人为的特征工程。
为了降低人为干预,使模型拥有在大规模帖子信息中更稳健的处理能力,同时提取更深层次的帖子、用户信息,深度学习模型大行其道,取得了极佳的效果。搜索排序部紧跟业界SOTA模型风向,落地了一系列排序模型,下文对深度模型的优化迭代路径做一个简要的阐述,介绍业界颇有成效的几个深度模型,并基于我们要优化的房产场景进行选型经验说明。
1. Wide&Deep
Google的排序模型Wide&Deep[1]从传统机器学习模型和深度模型的优势出发,既拥有LR的精准化推荐能力,也同时保持DNN模型的模糊推荐优势。
如图3所示,Wide&Deep可以看做两个模型的组合,左侧部分为LR模型,将输入的特征数据做加权整合,部分特征经过Embedding Layer转为one-hot编码馈入模型。由于特征输入直接反馈输出,保留了大量原始信息,模型挖掘到的用户兴趣,更偏向具体特征或帖子间的关联信息,如果训练数据中,酒仙桥和望京的房源帖共现频率较高,那么用户搜索酒仙桥时,模型会同时赋予望京房源更高的排序权重。这种直接从历史数据挖掘到的特征相关性,是低层特征信息,当用户复现某个历史行为时,模型能够拟合用户兴趣,表现出对特征的良好记忆性(Memorization)。
右侧部分是典型的DNN模型,负责获取用户兴趣的抽象表征。用于排序的特征数据大多比较稀疏,有些id类特征维度超过百万,因此在输入DNN模型前,通过Embedding Layer来降维特征,将高维稀疏特征转换到低维稠密特征。经过多层信息抽取,模型挖掘到的用户兴趣,会偏向特征组合得到的抽象表征,是高层特征信息,当用户产生历史数据没有出现过的新行为时,模型会平滑排序结果,表现出对特征的良好泛化性(Generalization)。
图3 Wide&Deep模型结构
2. DeepFM
Wide&Deep模型展现的记忆加泛化性能,在排序上取得了很好的效果,但作为组件之一的LR部分,挖掘到的用户兴趣对交叉信息不够友好。在机器学习模型优化中,使用交叉信息的方式通常是人为构建特征和特征间的组合,形成新特征表示相关关系,然而这部分工作是复杂且繁琐的。DeepFM[2]为了解决这个问题,引入了机器学习的FM模型,替换掉LR部分,形成FM&Deep结构,如图4所示。
图4 DeepFM模型结构
FM部分包含了加权求和的一阶信息和向量内积的二阶信息,自动进行特征交叉信息的提取,相比Wide&Deep在低层特征的使用上更合理。且Deep部分和FM部分共享Embedding Layer的输出,在计算复杂度上优化了模型。
3.DCN
DCN[3]的优化思路与DeepFM大体一致,既然Wide&Deep在低层特征使用时,无法提供更高阶的特征,必须依赖人工来构建交叉信息,那么交叉信息的提取,就从机器学习模型转到深度学习模型。因此相比DeepFM在Wide&Deep的基础上对LR部分的结构改进,DCN更进一步的替换LR部分为类DNN结构。
具体结构如图5所示,最明显的结构改变是左侧的类DNN模型。区别于右侧DNN的是,每一个隐含层除了接受前一层的输入外,会同步接受原始输入层的特征,从而实现特征信息的高阶交叉。对比DeepFM,DCN在低层特征的信息提取上,能够挖掘特征更高阶的交叉信息,同时由于DNN结构对矩阵计算的友好性,计算效率上较DeepFM更有优势。
图5 DCN模型结构
4.DIN
机器学习模型Xgboost在租房业务现有离线特征上的重要性排序如图6所示,红色透明框标识出的是基于用户历史行为统计得到的个性化特征,可以看出用户历史兴趣是影响租房场景下模型排序效果的重要因素。
图6 Xgboost特征重要性排序
阿里基于相似的业务理解,为更充分的挖掘用户历史兴趣,提出了DIN[4]模型,具体结构如图7所示。先前的模型在使用用户历史兴趣相关特征时,没有考虑候选贴的差异性,对于候选的每个帖子,都提取了相同的历史兴趣信息,DIN通过引入Attention机制,提升了模型对于用户历史兴趣的建模能力,构造了更合理的兴趣表征。
图7 DIN模型结构
DIN的核心是Attention Layer,候选贴和用户历史行为中的每个帖子发生交互,抑制无关的历史行为信息,加强和候选贴相似的历史信息,相比先前DNN模型中使用的用户历史统计信息而言,建模的用户兴趣更加准确,做到了千人千面,候选贴间的差异信息得到了更好的挖掘。
此外,先前模型在使用用户的历史行为信息时,依赖的都是基于人工统计的个性化信息。以租房业务而言,图6中重要性较高的ARPrrpcommunity特征,含义为用户对当前候选贴小区的偏好程度,我们预先统计了用户过去一周内点击过的帖子小区及次数,如用户之前看过将府家园、北窑地的一些房源贴,候选贴中若出现将府家园的小区信息,就表明一定程度上匹配了用户的兴趣,最终表现为一定的数值(点击次数)。这种建模方式仍旧依赖了人工的特征工程,当原始特征进行扩充时,对应的个性化统计信息需要扩充数倍,是繁复且冗杂的。
DIN使用用户历史行为信息的方式,是保留用户行为的序列信息,然后由模型自动进行交互信息的抽取,不再需要额外的人工干预过程,大幅降低了特征工程的复杂度。
5.DIEN
在DIN的基础上,阿里迭代了DIEN[5]模型,用来进一步抽取用户历史兴趣信息。DIN使用了用户历史行为序列,但只关注到了序列中和候选贴相关的特征交互信息,忽略了序列中还包含了用户行为的先后信息,这个信息会反映用户兴趣的迁移变化过程。比如用户搜索了丽都壹号的房源,浏览了一段时间后,发现自身预算有限,便转向搜索位置更远的北窑地,同时对于房源施加了一居室、精装修等更严格的要求,这种兴趣转换是DIN无法捕获的,因此DIEN添加了额外结构来解决这个问题,具体结构如图8所示。
图8 DIEN模型结构
相对DIN,DIEN在输入特征的处理中,改变了用户历史行为序列的提取逻辑,构建了兴趣提取层(Interest Extract Layer)来捕获用户历史行为中的帖子联系,GRU是NLP中抽取长序列信息的常用结构,DIEN引入GRU以提取用户对历史行为的兴趣。初步提取的兴趣表征,继续通过兴趣发展层(Interest Evolving Layer)加工,兴趣发展层包含了AUGRU和Attention结构,核心在于抽取兴趣的变化。AUGRU是加入了Attention分数的GRU,用来捕获与当前候选贴相关的兴趣变化。当前候选贴的特征只在发展层进行Attention调权,也表明DIEN的核心思想是提取用户历史行为序列中,与当前候选贴相关的兴趣变化,相对DIN更进一步的考虑了用户历史行为中存在的兴趣信息。
上述模型的发展路径,大致可以归结为:如何有效的降低人工干预,使用模型自动获取特征数据的信息,其中不止考虑特征间的交叉信息获取,还考虑了更加充沛的输入信息,使模型更加合理的构建用户兴趣。
我们考虑模型选型时,相比模型间的性能对比,更重要的是对业务场景的理解。先前的机器学习模型迭代时,用户历史行为统计得到的个性化信息,对线上排序性能的提升很有效果,因此相比致力于交叉信息获取的模型,选择了对用户历史行为更加友好的DIN和DIEN模型,进一步将人工统计特征向模型自动提取过渡。
数据样本构建
我们构建的离线样本数据,正如图7或8所示,有几大类特征:用户维度、帖子维度和补充上下文特征,帖子维度的特征又包含当前候选贴和用户历史序列两类。
1.已有基础特征
基于机器学习模型迭代建立的数据流程,我们在租房场景下构建的特征体系如下表所示。围绕用户,构造了用户当前访问状态相关的信息,并以24小时为限,统计了用户近期浏览过的帖子信息,建立了表达用户实时兴趣的个性化统计特征,这部分实时统计特征落盘后,以180天为周期统计得到用户的历史个性化统计特征。
帖子维度除了帖子id、位置等常规信息,主要关注了具体的属性信息,如价格、面积、朝向、设施等,这些属性区分的较为细致,在租房场景下基本覆盖了可见信息。虽然模型可以自动抽象特征信息,但业务上的关键特征还是需要人为来把控,合理且全面的覆盖对模型的效果提升极为关键,有时一个新的合理信息加入,比模型参数调整的效果更佳。以租房的业务优化经验,新加入用户搜索位置和房源位置的距离度量后,补充了用户的位置兴趣偏好,线下auc提升1.13%,效果还是比较明显的。此外,帖子维度利用候选贴的属性特征和用户维度的历史行为统计特征发生交互,建模了用户对当前候选贴的偏好兴趣度。
上下文特征属于补充信息,涵盖了基于帖子及当前曝光位置综合统计的CTR、CVR信息,统计信息分为实时、历史两部分,实时统计的时间窗口为7天,历史统计为30天,得到的点击或转化信息对于时间叠加了一定的衰减系数,并经过了贝叶斯平滑,保证统计信息在长时间跨度和低曝光量下的可靠性。此外,对帖子的时效性用曝光和刷新的时间差来表示。
大类****具体特征用户维度用户id,如imei用户访问时间用户搜索query、关键词等用户行为统计,如对价格、面积等偏好帖子维度帖子id帖子点击或转化行为帖子位置,包括全局位置、当前页面等房源具体信息,包括价格、面积等房源所在经纬度、城市、区域等用户搜索位置与房源的距离与用户行为统计的匹配信息,包括偏好值、是否用户最偏好等上下文统计的历史及实时CTR、CVR信息曝光时间及分段信息、曝光与刷新时间差、有效曝光标识等类目id、页面刷新id等
2.用户序列特征
我们对于DIN、DIEN模型的输入特征需求,新构建了基于Flink+Kafka架构的用户历史行为序列。为保留尽可能丰富的用户序列信息,采用了用户历史点击序列而非转化序列。序列中每一个历史贴,存储了帖子id及帖子的属性值如面积、价格、朝向等信息,这部分信息完全对齐候选贴的属性信息。
对于时间窗口3、5、7天的用户点击序列,统计了一天数据的序列长度分布,如图9所示。可以看出,序列长度为50时,覆盖超过80%的用户,排除长尾和异常数据,已经足够对用户在一周内的兴趣进行建模,因此我们线上存储的用户序列特征,最大截断长度设置为50,超过50时新序列替换距当前最久的一条序列数据。同时,我们不设置序列的过期时间,对非活跃用户而言,可以保留较长时间的历史行为,对活跃用户而言,基本保留了一周内的实时兴趣。
图9 用户历史点击序列统计
用户序列线上实时更新并落入HDFS,同步记录落盘的时间戳,离线构建样本时,依据序列日志的落盘时间戳和样本日志的曝光时间戳来获取实时序列,对同一用户的所有序列日志先按照时间戳排序(由新到旧),在小于曝光时间戳的序列日志中抽取最接近的一条,同时判断用户sessionid是否相同,不相同且时间最接近的认为是线上实时取到的序列日志,这样基本保证线上线下的用户序列特征一致性,缓解线上序列特征的时间穿越问题。
3.样本离线结构
模型的离线样本产出结构如图10所示,分为采样、特征抽取、特征工程、模型训练几个部分。
图10 模型离线样本产出结构
采样模块用于抽取具体场景数据并预处理,同时控制正负样本的比例,以租房场景而言,离线正负样本比例一般控制在1:4~1:5间效果较好。特征抽取用来获取模型需要的具体特征,对于缺失值和异常值,我们目前统一采用默认值替换方式,默认值依赖线下配置文件的具体指定。特征工程部分主要有归一化、分桶、哈希、类别取值等方式,同时将默认值参与特征工程转换,保证特征输出没有负值(模型输入做embedding不支持负值索引)。模型训练部分构建训练、验证和测试样本,并进行精度评估。我们在评估模型效果时,采用了GAUC[4]评价标准,AUC是对于全体样本排序后计算的一个值,反映了模型对于整体样本的排序能力。然而实际的线上排序,是对于单一用户的曝光,GAUC考虑的是各用户的评价集合,相对AUC更接近线上效果的评估标准。GAUC先计算各个用户自己的AUC,然后加权平均,目前我们的权重采用滤掉单一样本(全为正或负)后的用户样本贴子量占比。
模型优化
针对58的租房场景,我们尝试在以下几个方面对DIN、DIEN模型做了一些调整,获得了不错的效果。
1.特征构建方式
对于原始模型,如图7或8所示,输入特征都经过Embedding Layer进行映射降维,对于原本低维的特征意义不大。因此,我们对低维类别特征采用one-hot编码,高维稀疏ID类特征进行embedding,连续特征归一化或者离散化后,依据维度高低进行embedding或者one-hot编码,最后在Attention Layer前concat全部特征。
2.预测正确性
最初实验时,发现模型预测结果随组装batch和序列填充长度变化很大,这就导致同条样本的结果变得不可信,乃至影响模型效果评估。经过研究,问题定位如下:
数据组装batch的影响
模型构建DNN部分时使用了Batch Normalization来缓解随机取的批次数据由于数据分布的差异导致的模型参数微调及模型训练效率降低问题。原生的tensorflow api实现BN层(tf.layers.batch_normalization)时,并不能做到参数的完全自动更新,对于数据的滑动均值、方差(moving_mean、moving_variance),只能通过手动更新,导出模型时这两个参数也需要额外读取保存。同时BN层在训练时和预测时有不同的处理逻辑,我们必须指定参数training来区分训练状态。
Dice[4]激活函数是对prelu的改进,可以看做添加了BN的prelu,动态调整梯度变化点适应不同的输入数据分布。由于加入了BN,带来了上述同样的问题,且原实现只考虑了训练情况,没有预测部分,我们基于tensorflow原生BN重新实现了Dice,解决了这一问题。
对于dropout而言,也存在训练和预测过程处理逻辑不一致问题,预测时我们不应该生效dropout以免输入数据不稳定。
序列填充长度的影响
用户历史序列拼装成一个批次数据时,由于不同用户的点击序列长度不同,我们以最长序列为基准,对同批次的短序列进行了0值填充,构建成相同维度的输入数据喂给模型。但是模型输入的特征,全部经过Embedding Layer进行编码,不论one-hot方式还是embedding方式,都会将填充的0值进行转换,最终表现为一个非零值的特征,这样相当于我们填充的序列长度也作为一个特征信息被模型学习。因此,我们利用用户序列的mask信息,对编码后的特征做了截取,保留了用户真实的序列信息。
调整后,模型组装数据方式对预测结果不产生影响,经过线下实验,auc相对提升0.94%,gauc相对提升1.37%,这个提升对于排序而言已经相当明显了。因此对于封装好的原生接口,我们在使用时需要把握参数的含义,了解清楚逻辑,否则很容易踩坑,这类问题还极难定位。对于开源的实现,我们应用到具体的业务场景上,也应先保证模型的实现正确,才能谈对业务的迭代优化。
3. 数据读取提速
为了充分使用GPU资源,我们调整原生的数据加载,使用tensorflow支持的dataset方式预处理数据,dataset可以并行处理数据,将耗时的预处理部分放在多个CPU进行处理,GPU的等待数据时间可以大大缩短,模型的实际训练效率得到了提升。调整dataset方式后,对于同样的batch size和一天的训练数据(约2000万),离线GPU利用率由10%提升至50%,模型训练时间由7小时降低到1小时,大大加快了模型优化迭代过程。
4.多目标
实际做排序优化的过程中,经常面对的问题是,优化目标是转化率的提升,但实际的用户转化行为很少,导致样本空间并不能真正代表线上数据分布,模型很难学习到正确的信息。但是若直接使用点击数据训练的模型,固然会对线上的CTR产生正向效果,对CVR的建模却是有偏的。我们考虑综合利用CTR和CVR的信息,构建了多目标模型,结构如图11所示(以DIN为例)。
图11 多目标模型结构
输入样本数据生成关于点击和转化各自的标签,模型中为每个任务单独构建DNN部分,共享特征Embedding Layer和Attention Layer的输出。对于CVR任务来说,输入的数据量扩增了数倍,且更逼近真实的样本分布,共享的输入信息也不会增加模型过多的参数量,同时CTR任务训练过程中同步作用在特征输入部分,能够纠正模型的偏差,为模型提供更多维度的信息。线上实际部署模型时,可以用一个多目标模型替代CTR、CVR单独训练的模型,实际的推理性能比单纯部署两个任务模型时更佳。
多目标训练的损失函数构造如下:
采用加权和作为整体loss,权重配比依赖预先在各自任务下训练得到的loss值,基本保持各自任务对loss的贡献相同。
阿里在ESMM[6]模型提出了CTR任务和CVR任务的级联关系,用户先点击到某个帖子,才会继续发生转化行为,并用连乘来构造总体损失,这个想法比较符合用户实际转化行为发生的场景,后续我们会进行尝试。
预测优化
我们在初步完成模型训练后,针对wpai提供的多个线上环境进行了压测,对相同的单目标DIN模型在batch size 10,单测试节点6核CPU 2G内存情况下,得到如下结论:
综合性能表现,CPU环境由于数据预处理和模型推断都在同一环境,不必经过CPU到GPU的数据传输,不论是耗时还是QPS均优于其余版本,因此我们选择了使用CPU环境进行模型部署。但上线后,发现测试环境的性能表现不能够完全对齐线上,由于线上环境流量复杂,会有瞬时高峰流量出现,实测的模型耗时相较线下会增长1~3ms左右,且长尾数据导致的模型超时会比较严重,最高达到5%左右,所以我们考虑工程实现上对模型预测过程进行优化。
1. 序列化数据格式转换
初版预测实现,我们针对模型的不同特征分组组装了预测请求数据,单独特征分组均采用List或List数据形式组装,后续将列表转换为基础数据类型数组,如int[]或float[],线下压测性能得到了较大幅度的提升,如图12所示。
图12 序列化数据格式性能对比
虽然只是很小的工程优化,线下预测性能已经得到了充分的扩展,使用简单的数据传输格式,SCF序列化效率会有比较好的提升。
2.用户序列简化
对于离线样本数据构建时,我们组装的数据是一个batch,由于用户不同导致用户的历史行为序列长度也有差异,所以通过填充短序列来构造了相同维度的序列数据进行预测。但在线上实际预测时,用户一个搜索请求发生时,我们需要对不同的候选贴进行排序,虽然帖子维度的特征各不相同,但都是对相同用户的响应,所以从用户维度的特征尤其是用户行为序列来看,这些数据是不必要考虑填充构造的。
我们对于用户维度的特征数据,如用户id、用户历史行为序列涵盖的帖子特征、mask信息等进行简化,序列化时只保留一个数据的信息,在预测数据预处理时再进行batch数据的填充。
上述工程实现的优化,使SCF序列化的数据量减小了90%,对应数据组装batch由10提升到20,线上超时率由3-5%降到0.5-0.7%,模型访问平均耗时降低5ms,具体对比如下图13所示。可以看到优化后模型超时量明显下降,能够更准确的评估线上模型迭代效果。
图13 预测优化前后模型耗时对比
线上效果
基于上述的优化思路,我们持续在线上对模型进行了迭代,主要的优化措施效果如下表所示,baseline为线上的Xgboost模型。
其中最优模型为采取了全部优化措施的多目标DIEN模型,可以看出相对线上基准Xgboost模型,在点击和转化上排序效果都获得了极大的提升。我们后续推全了最优模型,线上的实际表现如图14所示,多目标DIEN模型相对线上Xgboost模型,无论点击率还是转化率的提升都相对稳定。
图14 10.5~10.13期间多目标DIEN模型线上统计
模型实际的线上预测表现如图15所示,在访问量有较大波动时,耗时相对稳定,batch为20的平均耗时在12ms以内,且模型超时量最大占比不超过0.2%,预测性能完全满足线上实时并发请求的需要。
图15 10.5一天模型线上访问性能表现
总结与展望
我们针对租房业务场景的排序优化目的,构建了从离线样本到线上预测的完整流程,考虑用户历史行为会包含更多的兴趣信息,选用了DIN、DIEN模型进行迭代优化。从数据特征、模型改进、预测优化上持续提升模型的性能表现。
在实际优化过程中,理解业务一直是我们的重点,只有充分的理解我们要研究的业务场景,才能准确的指导我们的优化方向。最后模型在线上的迭代提升,很大程度上依赖了对业务特征和业务数据的把握。
后续我们的工作重点,会继续放在深入挖掘业务场景上。对于帖子id这类超大规模稀疏特征,拆分embedding在离线完成以降低线上耗时;对于租房场景而言,用户看到的首图也是很重要的特征信息,考虑CNN提取特征融入排序模型;对于58其他垂类,例如招聘、商业地产等业务场景,应用并持续扩充深度模型的排序能力。
同时我们也会持续关注业界的前沿研究,升级现有数据和模型架构,适应多种类模型的落地需求,致力于持续对外提供丰富且稳定的排序能力。
作者简介:
白博,58同城TEG—搜索排序部算法高级工程师,专注于58同城垂类搜索排序优化,负责深度学习模型的具体场景落地与迭代,19年硕士毕业于太原理工大学。
部门简介:
58同城TEG搜索排序部,旨在打造搜索技术中台�
- 原文作者:知识铺
- 原文链接:https://geek.zshipu.com/post/%E4%BA%92%E8%81%94%E7%BD%91/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%9C%A8%E5%90%8C%E5%9F%8E%E7%A7%9F%E6%88%BF%E6%90%9C%E7%B4%A2%E6%8E%92%E5%BA%8F%E7%9A%84%E5%BA%94%E7%94%A8/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。
- 免责声明:本页面内容均来源于站内编辑发布,部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性,如涉及版权等问题,请立即联系客服进行更改或删除,保证您的合法权益。转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。也可以邮件至 sblig@126.com