不多说,直接上干货!

常见的推荐算法

  1、基于关系规则的推荐

  2、基于内容的推荐

  3、人口统计式的推荐

  4、协调过滤式的推荐

  协调过滤算法,是一种基于群体用户或者物品的典型推荐算法,也是目前常用的推荐算法中最常用和最经典的算法。

  协调过滤算法主要有两种:

    用户对物品:  考查具有相同爱好的用户相同物品的评分标准进行计算;

    物品对用户:  考查具有相同物质的物品从而推荐给选择了某件物品的用户。

相似度度量(基于欧几里得距离的相似度计算和基于余弦角度的相似度计算)

    (1)、基于欧几里得距离的相似度计算

        欧几里得,是三维空间中两个点的真实距离。

        欧几里得相似度计算是一种基于用户之间直线距离的计算方式。在相似度计算中,不同的物品或者用户可以将其定义为不同的坐标点,而特定目标定位为坐标原点。

        在实际应用中,常常使用欧几里得距离的倒数作为相似度,即 1/ (d+1) 作为近似值。

    (2)、基于余弦角度的相似度计算    

        不同的物品或者用户作为不同的坐标点,但不能为坐标原点。

  其实,还有其他的算法,也可以来相似度度量

  

基于欧几里得距离的相似度计算和基于余弦角度的相似度计算的区别

  欧几里得相似度是以目标绝对距离作为衡量的标准,余弦相似度以目标差异的大小作为衡量标准。

  欧几里得相似度注重目标之间的差异,与目标在空间中的位置直接相关。余弦相似度是不同目标在空间中的夹角,更加表现在前进趋势上的差异。

  欧几里得相似度和余弦相似度具有不同的计算方法和描述特征,一般来说,欧几里得相似度用来表现不同目标的绝对差异性,分析目标之间的相似度与差异情况。而余弦相似度更多的是对目标从方向趋势上区分,对特定坐标数字不敏感。

基于余弦相似度计算不同用户之间相似性

  步骤是:  

  (1)输入数据  

  (2)建立相似度算法公式

  (3)计算不同用户之间的相似度

   CollaborativeFilteringSpark.scala

package zhouls.bigdata.chapter5import org.apache.spark.{SparkConf, SparkContext}
import scala.collection.mutable.Mapobject CollaborativeFilteringSpark {val conf = new SparkConf().setMaster("local").setAppName("CollaborativeFilteringSpark ")    //设置环境变量val sc = new SparkContext(conf)                                 //实例化环境val users = sc.parallelize(Array("aaa","bbb","ccc","ddd","eee"))       //设置用户val films = sc.parallelize(Array("smzdm","ylxb","znh","nhsc","fcwr"))    //设置电影名
   val source = Map[String,Map[String,Int]]()                //使用一个source嵌套map作为姓名电影名和分值的存储val filmSource = Map[String,Int]()                     //设置一个用以存放电影分的mapdef getSource(): Map[String,Map[String,Int]] = {            //设置电影评分val user1FilmSource = Map("smzdm" -> 2,"ylxb" -> 3,"znh" -> 1,"nhsc" -> 0,"fcwr" -> 1)val user2FilmSource = Map("smzdm" -> 1,"ylxb" -> 2,"znh" -> 2,"nhsc" -> 1,"fcwr" -> 4)val user3FilmSource = Map("smzdm" -> 2,"ylxb" -> 1,"znh" -> 0,"nhsc" -> 1,"fcwr" -> 4)val user4FilmSource = Map("smzdm" -> 3,"ylxb" -> 2,"znh" -> 0,"nhsc" -> 5,"fcwr" -> 3)val user5FilmSource = Map("smzdm" -> 5,"ylxb" -> 3,"znh" -> 1,"nhsc" -> 1,"fcwr" -> 2)source += ("aaa" -> user1FilmSource)                //对人名进行存储source += ("bbb" -> user2FilmSource)                 //对人名进行存储source += ("ccc" -> user3FilmSource)                 //对人名进行存储source += ("ddd" -> user4FilmSource)                 //对人名进行存储source += ("eee" -> user5FilmSource)                 //对人名进行存储source                                        //返回嵌套map
   }//两两计算分值,采用余弦相似性def getCollaborateSource(user1:String,user2:String):Double = {val user1FilmSource = source.get(user1).get.values.toVector        //获得第1个用户的评分val user2FilmSource = source.get(user2).get.values.toVector        //获得第2个用户的评分val member = user1FilmSource.zip(user2FilmSource).map(d => d._1 * d._2).reduce(_ + _).toDouble            //对公式分子部分进行计算val temp1  = math.sqrt(user1FilmSource.map(num => {            //求出分母第1个变量值math.pow(num,2)                                        //数学计算          }).reduce(_ + _))                                        //进行叠加val temp2  = math.sqrt(user2FilmSource.map(num => {            ////求出分母第2个变量值math.pow(num,2)                                     //数学计算}).reduce(_ + _))                                        //进行叠加val denominator = temp1 * temp2                            //求出分母member / denominator                                    //进行计算
}def main(args: Array[String]) {getSource()                                            //初始化分数val name = "bbb"                                        //设定目标对象users.foreach(user =>{                                    //迭代进行计算println(name + " 相对于 " + user +"的相似性分数是:"+ getCollaborateSource(name,user))})}}

bbb 相对于 aaa的相似性分数是:0.7089175569585667
bbb 相对于 bbb的相似性分数是:1.0000000000000002
bbb 相对于 ccc的相似性分数是:0.8780541105074453
bbb 相对于 ddd的相似性分数是:0.6865554812287477
bbb 相对于 eee的相似性分数是:0.6821910402406466

  当然,这里大家也可以进一步修改程序。

  CollaborativeFilteringSpark.scala

package zhouls.bigdata.chapter5import org.apache.spark.{SparkConf, SparkContext}
import scala.collection.mutable.Mapobject CollaborativeFilteringSpark {val conf = new SparkConf().setMaster("local").setAppName("CollaborativeFilteringSpark ")    //设置环境变量val sc = new SparkContext(conf)                                 //实例化环境val users = sc.parallelize(Array("aaa","bbb","ccc","ddd","eee"))       //设置用户val films = sc.parallelize(Array("smzdm","ylxb","znh","nhsc","fcwr"))    //设置电影名
   val source = Map[String,Map[String,Int]]()                //使用一个source嵌套map作为姓名电影名和分值的存储val filmSource = Map[String,Int]()                     //设置一个用以存放电影分的mapdef getSource(): Map[String,Map[String,Int]] = {            //设置电影评分val user1FilmSource = Map("smzdm" -> 2,"ylxb" -> 3,"znh" -> 1,"nhsc" -> 0,"fcwr" -> 1)val user2FilmSource = Map("smzdm" -> 1,"ylxb" -> 2,"znh" -> 2,"nhsc" -> 1,"fcwr" -> 4)val user3FilmSource = Map("smzdm" -> 2,"ylxb" -> 1,"znh" -> 0,"nhsc" -> 1,"fcwr" -> 4)val user4FilmSource = Map("smzdm" -> 3,"ylxb" -> 2,"znh" -> 0,"nhsc" -> 5,"fcwr" -> 3)val user5FilmSource = Map("smzdm" -> 5,"ylxb" -> 3,"znh" -> 1,"nhsc" -> 1,"fcwr" -> 2)source += ("aaa" -> user1FilmSource)                //对人名进行存储source += ("bbb" -> user2FilmSource)                 //对人名进行存储source += ("ccc" -> user3FilmSource)                 //对人名进行存储source += ("ddd" -> user4FilmSource)                 //对人名进行存储source += ("eee" -> user5FilmSource)                 //对人名进行存储source                                        //返回嵌套map
   }//两两计算分值,采用余弦相似性def getCollaborateSource(user1:String,user2:String):Double = {val user1FilmSource = source.get(user1).get.values.toVector        //获得第1个用户的评分val user2FilmSource = source.get(user2).get.values.toVector        //获得第2个用户的评分val member = user1FilmSource.zip(user2FilmSource).map(d => d._1 * d._2).reduce(_ + _).toDouble            //对公式分子部分进行计算val temp1  = math.sqrt(user1FilmSource.map(num => {            //求出分母第1个变量值math.pow(num,2)                                        //数学计算          }).reduce(_ + _))                                        //进行叠加val temp2  = math.sqrt(user2FilmSource.map(num => {            ////求出分母第2个变量值math.pow(num,2)                                     //数学计算}).reduce(_ + _))                                        //进行叠加val denominator = temp1 * temp2                            //求出分母member / denominator                                    //进行计算
}def main(args: Array[String]) {getSource()                                            //初始化分数var name = "bbb"                                        //设定目标对象users.foreach(user =>{                                    //迭代进行计算println(name + " 相对于 " + user +"的相似性分数是:"+ getCollaborateSource(name,user))})println()name = "aaa"     users.foreach(user => {//迭代进行计算println(name + " 相对于 " + user + "的相似性分数是:" + getCollaborateSource(name, user))})}}

  或者,也可以写下程序,如下

UserSimilar.scala
package zhouls.bigdataimport org.apache.log4j.{Level, Logger}
import org.apache.spark.{SparkContext, SparkConf}
import scala.collection.mutable.Map

object UserSimilar {//屏蔽不必要的日志显示在终端上Logger.getLogger("org.apache.spark").setLevel(Level.WARN)Logger.getLogger("org.apache.eclipse.jetty.server").setLevel(Level.OFF)//程序入口val conf = new SparkConf().setMaster("local[1]").setAppName(this.getClass().getSimpleName().filter(!_.equals('$')))println(this.getClass().getSimpleName().filter(!_.equals('$')))val sc = new SparkContext(conf)//设置用户名val users = sc.parallelize(Array("张三", "李四", "王五", "赵六", "阿七"))//设置电影名val films = sc.parallelize(Array("逆战", "人间", "鬼屋", "西游记", "雪豹"))//使用一个source嵌套map作为姓名电影名和分值的存储val source = Map[String, Map[String, Int]]()//设置一个用以存放电影分的mapval filmSource = Map[String, Int]()def getSource(): Map[String, Map[String, Int]] = {//设置电影评分val user1FilmSource = Map("逆战" -> 2, "人间" -> 3, "鬼屋" -> 1, "西游记" -> 0, "雪豹" -> 1)val user2FilmSource = Map("逆战" -> 1, "人间" -> 2, "鬼屋" -> 2, "西游记" -> 1, "雪豹" -> 4)val user3FilmSource = Map("逆战" -> 2, "人间" -> 1, "鬼屋" -> 0, "西游记" -> 1, "雪豹" -> 4)val user4FilmSource = Map("逆战" -> 3, "人间" -> 2, "鬼屋" -> 0, "西游记" -> 5, "雪豹" -> 3)val user5FilmSource = Map("逆战" -> 5, "人间" -> 3, "鬼屋" -> 1, "西游记" -> 1, "雪豹" -> 2)//对人名进行储存source += ("张三" -> user1FilmSource)source += ("李四" -> user2FilmSource)source += ("王五" -> user3FilmSource)source += ("赵六" -> user4FilmSource)source += ("阿七" -> user5FilmSource)//返回嵌套map
    source}//两两计算分值,采用余弦相似性def getCollaborateSource(user1: String, user2: String): Double = {//获得1,2两个用户的评分val user1FilmSource = source.get(user1).get.values.toVectorval user2FilmSource = source.get(user2).get.values.toVector//对公式部分分子进行计算val member = user1FilmSource.zip(user2FilmSource).map(d => d._1 * d._2).reduce(_ + _).toDouble//求出分母第一个变量值val temp1 = math.sqrt(user1FilmSource.map(num => {math.pow(num, 2)}).reduce(_ + _))//求出分母第二个变量值val temp2 = math.sqrt(user2FilmSource.map(num => {math.pow(num, 2)}).reduce(_ + _))//求出分母val denominator = temp1 * temp2//进行计算member / denominator}def main(args: Array[String]) {//初始化分数
    getSource()val name1 = "张三"val name2 = "李四"val name3 = "王五"val name4 = "赵六"val name5 = "阿七"users.foreach(user => {println(name1 + " 相对于 " + user + " 的相似性分数是 " + getCollaborateSource(name1, user) )})println("--------------------------------------------------------------------------")users.foreach(user => {println(name2 + " 相对于 " + user + " 的相似性分数是 " + getCollaborateSource(name2, user) )})println("--------------------------------------------------------------------------")users.foreach(user => {println(name3 + " 相对于 " + user + " 的相似性分数是 " + getCollaborateSource(name3, user) )})println("--------------------------------------------------------------------------")users.foreach(user => {println(name4 + " 相对于 " + user + " 的相似性分数是 " + getCollaborateSource(name4, user) )})println("--------------------------------------------------------------------------")users.foreach(user => {println(name5 + " 相对于 " + user + " 的相似性分数是 " + getCollaborateSource(name5, user) )})}}

  结果是

"C:\Program Files\Java\jdk1.8.0_77\bin\java" -Didea.launcher.port=7534 "-Didea.launcher.bin.path=D:\Program Files (x86)\JetBrains\IntelliJ IDEA 15.0.5\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_77\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_77\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_77\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_77\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_77\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_77\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_77\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_77\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_77\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_77\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_77\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_77\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_77\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_77\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_77\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_77\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_77\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_77\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_77\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_77\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_77\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_77\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_77\jre\lib\rt.jar;G:\location\spark-mllib\out\production\spark-mllib;C:\Program Files (x86)\scala\lib\scala-actors-migration.jar;C:\Program Files (x86)\scala\lib\scala-actors.jar;C:\Program Files (x86)\scala\lib\scala-library.jar;C:\Program Files (x86)\scala\lib\scala-reflect.jar;C:\Program Files (x86)\scala\lib\scala-swing.jar;G:\home\download\spark-1.6.1-bin-hadoop2.6\lib\datanucleus-api-jdo-3.2.6.jar;G:\home\download\spark-1.6.1-bin-hadoop2.6\lib\datanucleus-core-3.2.10.jar;G:\home\download\spark-1.6.1-bin-hadoop2.6\lib\datanucleus-rdbms-3.2.9.jar;G:\home\download\spark-1.6.1-bin-hadoop2.6\lib\spark-1.6.1-yarn-shuffle.jar;G:\home\download\spark-1.6.1-bin-hadoop2.6\lib\spark-assembly-1.6.1-hadoop2.6.0.jar;G:\home\download\spark-1.6.1-bin-hadoop2.6\lib\spark-examples-1.6.1-hadoop2.6.0.jar;D:\Program Files (x86)\JetBrains\IntelliJ IDEA 15.0.5\lib\idea_rt.jar" com.intellij.rt.execution.application.AppMain mllib.CollaborativeFilteringSpark
CollaborativeFilteringSpark
Using Spark's default log4j profile: org/apache/spark/log4j-defaults.properties
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/G:/home/download/spark-1.6.1-bin-hadoop2.6/lib/spark-assembly-1.6.1-hadoop2.6.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/G:/home/download/spark-1.6.1-bin-hadoop2.6/lib/spark-examples-1.6.1-hadoop2.6.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
16/08/04 20:41:49 INFO Slf4jLogger: Slf4jLogger started
16/08/04 20:41:49 INFO Remoting: Starting remoting
16/08/04 20:41:49 INFO Remoting: Remoting started; listening on addresses :[akka.tcp://sparkDriverActorSystem@192.168.1.100:8380]
张三 相对于 张三 的相似性分数是 0.9999999999999999
张三 相对于 李四 的相似性分数是 0.7089175569585667
张三 相对于 王五 的相似性分数是 0.6055300708194983
张三 相对于 赵六 的相似性分数是 0.564932682866032
张三 相对于 阿七 的相似性分数是 0.8981462390204985
--------------------------------------------------------------------------
李四 相对于 张三 的相似性分数是 0.7089175569585667
李四 相对于 李四 的相似性分数是 1.0000000000000002
李四 相对于 王五 的相似性分数是 0.8780541105074453
李四 相对于 赵六 的相似性分数是 0.6865554812287477
李四 相对于 阿七 的相似性分数是 0.6821910402406466
--------------------------------------------------------------------------
王五 相对于 张三 的相似性分数是 0.6055300708194983
王五 相对于 李四 的相似性分数是 0.8780541105074453
王五 相对于 王五 的相似性分数是 1.0
王五 相对于 赵六 的相似性分数是 0.7774630169639036
王五 相对于 阿七 的相似性分数是 0.7416198487095662
--------------------------------------------------------------------------
赵六 相对于 张三 的相似性分数是 0.564932682866032
赵六 相对于 李四 的相似性分数是 0.6865554812287477
赵六 相对于 王五 的相似性分数是 0.7774630169639036
赵六 相对于 赵六 的相似性分数是 1.0
赵六 相对于 阿七 的相似性分数是 0.738024966423108
--------------------------------------------------------------------------
阿七 相对于 张三 的相似性分数是 0.8981462390204985
阿七 相对于 李四 的相似性分数是 0.6821910402406466
阿七 相对于 王五 的相似性分数是 0.7416198487095662
阿七 相对于 赵六 的相似性分数是 0.738024966423108
阿七 相对于 阿七 的相似性分数是 0.9999999999999998
16/08/04 20:41:51 INFO RemoteActorRefProvider$RemotingTerminator: Shutting down remote daemon.  Process finished with exit code 0  

转载于:https://www.cnblogs.com/zlslch/p/7477146.html

Spark Mllib里相似度度量(基于余弦相似度计算不同用户之间相似性)(图文详解)...相关推荐

  1. Windows系统里Oracle 11g R2 Client(64bit)的下载与安装(图文详解)

    1.全网最详细的Windows系统里Oracle 11g R2 Client(64bit)的下载与安装(图文详解) 方法地址:https://www.cnblogs.com/zlslch/p/9273 ...

  2. Spark Mllib里的如何对单个数据集用斯皮尔曼计算相关系数

    不多说,直接上干货! import org.apache.spark.mllib.stat.Statistics 具体,见 Spark Mllib机器学习实战的第4章 Mllib基本数据类型和Mlli ...

  3. CentOS系统里如何正确取消或者延长屏幕保护自动锁屏功能(图文详解)

    不多说,直接上干货! 对于我这里想说的是,分别从CentOS6.X  和  CentOS7.X来谈及. 1. 问题:默认启动屏幕保护 问题描述: CentOS系统在用户闲置一段时间(默认为5分钟)后, ...

  4. 基于windows子系统WSL2搭建openharmony开发环境(图文详解)

    WSL(Windows Subsystem for Linux)是Microsoft弄出来的windows下的linux子系统,主要目的也就是为了给开发者提供便利,抢占macOs的市场.想必大家对它都 ...

  5. php html5日期插件,基于jQuery和HTML5的日历时钟插件 的图文详解

    jQuery是一个当前依然非常流行的Web前端JavaScript框架,这次我们要分享的就是基于jQuery的日历时钟插件,部分日历插件还是基于HTML5技术实现的,因此动画效果都还不错.有兴趣的朋友 ...

  6. Snort里如何将读取的包记录存到指定的目录下(图文详解)

    不多说,直接上干货! 比如,在/root/log目录下. [root@datatest ~]# snort -dve -l /root/log 需要注意: 1) /log目录需要你自己建立,并修改权限 ...

  7. 全网最全的Windows下Anaconda2 / Anaconda3里正确下载安装爬虫框架Scrapy(离线方式和在线方式)(图文详解)...

    不多说,直接上干货! 参考博客 全网最全的Windows下Anaconda2 / Anaconda3里正确下载安装OpenCV(离线方式和在线方式)(图文详解) 第一步:首先,提示升级下pip 第二步 ...

  8. 基于余弦相似度的改进蝴蝶优化算法

    文章目录 一.理论基础 1.蝴蝶优化算法 2.改进蝴蝶优化算法 (1)基于余弦相似度位置更新策略 (2)根据适应度动态调整转换概率策略 (3)自适应混合惯性权重 二.MSBOA算法步骤 三.仿真实验与 ...

  9. Spark Mllib里的分布式矩阵(行矩阵、带有行索引的行矩阵、坐标矩阵和块矩阵概念、构成)(图文详解)...

    不多说,直接上干货! Distributed matrix : 分布式矩阵 一般能采用分布式矩阵,说明这数据存储下来,量还是有一定的.在Spark Mllib里,提供了四种分布式矩阵存储形式,均由支持 ...

  10. 【推荐系统->相似度算法】余弦相似度

    转自相似度算法之余弦相似度 余弦距离,也称为余弦相似度,是用向量空间中两个向量夹角的余弦值作为衡量两个个体间差异的大小的度量. 余弦值越接近1,就表明夹角越接近0度,也就是两个向量越相似,这就叫&qu ...

最新文章

  1. 记录gulp报错The following tasks did not complete: cssmin或类似任务
  2. 系统性能测试--杨建旭
  3. 数据分析之numpy
  4. 学习yield《转》
  5. java冒泡怎么写_java 冒泡 又一种写法
  6. hdfs 数据迁移_对象存储BOS发布全新工具,加速自建HDFS到云端的访问速度
  7. openmv探索_5_openmv读取的数据输出到外界
  8. 全自动高清录播服务器,全自动高清录播服务器 高清录播系统 一体化操作;易使用 操作简便...
  9. 外观模式又叫门面模式?
  10. mac vim映射esc_如何通过重新映射大写锁定来获取Mac的Esc键
  11. python:实现base64加密和base64解密算法(附完整源码)
  12. android统计app使用时间段,GitHub - yaozs/UseTimeStatistic: Android 系统中统计各个app的使用时长以及使用次数...
  13. 5G端到端时延要求1ms是个什么概念?
  14. 【Linux后端开发必问】操作系统系列(Linux常用命令、文件权限修改、静态与动态库的制作)
  15. 【从0开始学GIS】ArcGIS中的绘图基础操作(三)
  16. Python实践4-守护线程
  17. 电商页面设计 只需懂六个字
  18. gmapping源码分析(转)
  19. Camstar 大数据之数据处理
  20. 计算机专业申请,美国TOP20计算机专业大学申请建议

热门文章

  1. 超高频手持机怎样选择才适合工作呢
  2. Apache Ignite(七):基于Ignite的企业级分布式并行计算
  3. 内连接,外连接,临时表,定义表,视图
  4. xcode,cocoa开发:如何使用第三方的dylib
  5. vgextend 扩容卷组,即把物理卷加入卷组
  6. c语言qsort函数对结构体的一级排序,sort和qsort函数对结构体的二级排序
  7. 软件压力测试的手段有注入错误吗,JMeter压力测试之环境搭建、脚本调试及报错解决方法(Linux版)...
  8. 深入理解android 博客,深入理解Android中ViewGroup
  9. 万用表测线路断点位置_万用表测电流口诀,正确使用方法
  10. java_web tomcat服务器的安装与配置