├── .gitattributes ├── .gitignore ├── README.md ├── data ├── import.rar ├── movie_data_import.sql ├── question │ ├── question_classification.txt │ ├── vocabulary.txt │ ├── 【0】评分.txt │ ├── 【10】某演员出演过哪些类型的电影.txt │ ├── 【11】演员A和演员B合作了哪些电影.txt │ ├── 【12】某演员一共演过多少电影.txt │ ├── 【13】演员出生日期.txt │ ├── 【1】上映.txt │ ├── 【2】风格.txt │ ├── 【3】剧情.txt │ ├── 【4】某电影有哪些演员出演.txt │ ├── 【5】演员简介.txt │ ├── 【6】某演员出演过的类型电影有哪些.txt │ ├── 【7】某演员演了什么电影.txt │ ├── 【8】演员参演的电影评分【大于】.txt │ └── 【9】演员参演的电影评分【小于】.txt └── 自定义词典.zip ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── appleyk │ │ ├── Application.java │ │ ├── controller │ │ ├── GenreController.java │ │ ├── MovieController.java │ │ ├── PageIndexController.java │ │ ├── PersonController.java │ │ └── QuestionController.java │ │ ├── node │ │ ├── BaseEntity.java │ │ ├── Genre.java │ │ ├── Movie.java │ │ └── Person.java │ │ ├── process │ │ └── ModelProcess.java │ │ ├── repository │ │ ├── GenreRepository.java │ │ ├── MovieRepository.java │ │ ├── PersonRepository.java │ │ └── QuestionRepository.java │ │ ├── result │ │ ├── ResponseMessage.java │ │ ├── ResponseResult.java │ │ └── ResultData.java │ │ └── service │ │ ├── QuestionService.java │ │ └── impl │ │ └── QuestionServiceImpl.java ├── resources │ ├── application.properties │ ├── hanlp.properties │ ├── logback-boot.xml │ └── templates │ │ └── index.html └── webapp │ └── WEB-INF │ └── web.xml └── test └── java ├── BayesTest.java └── HanLPTest.java /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sql linguist-language=java 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | target 3 | Spring-Neo4j-Movie.iml 4 | opt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spring-Boot-KBQA 2 | 3 | 以Spring Boot框架为载体,通过集成hanLP、neo4j、spark-mllib实现基于电影知识图谱的简易问答系统。 4 | 5 | 首先启动springboot后在浏览器中访问8080端口,接着在网页上输入关于电影的一些问题,前端页面通过AJAX请求将问题发送到后端接口,后端接收到请求后,先加载问题模板、字典、分类模型及自定义字典;再对问题分词后利用分类模型将原问题匹配到对应的问题模板上;最后针对不同种类的问题从图数据库neo4j中查询对应的答案并返回。 6 | 7 | # 数据 8 | - mysql (/data/movie_data_import.sql) 9 | - neo4j (先将mysql的数据导出csv文件,再导入到neo4j中,有利于比较两种数据库的关系,图数据库更适合对关系的处理。也可直接将/data/import.rar压缩包内的文件直接导入到neo4j中) 10 | ``` 11 | 12 | 找到neo4j的安装路径,并在D:\neo4j-community-3.4.0\目录下创建import目录 13 | 完整路径如下D:\neo4j-community-3.4.0\import 14 | 因为neo4j支持导入csv文件,其默认目录入口是 ...\import 15 | 16 | 17 | //导入节点 电影类型 == 注意类型转换 18 | LOAD CSV WITH HEADERS FROM "file:///genre.csv" AS line 19 | MERGE (p:Genre{gid:toInteger(line.gid),name:line.gname}) 20 | 21 | 22 | //导入节点 演员信息 23 | LOAD CSV WITH HEADERS FROM 'file:///person.csv' AS line 24 | MERGE (p:Person { pid:toInteger(line.pid),birth:line.birth, 25 | death:line.death,name:line.name, 26 | biography:line.biography, 27 | birthplace:line.birthplace}) 28 | 29 | 30 | // 导入节点 电影信息 31 | LOAD CSV WITH HEADERS FROM "file:///movie.csv" AS line 32 | MERGE (p:Movie{mid:toInteger(line.mid),title:line.title,introduction:line.introduction, 33 | rating:toFloat(line.rating),releasedate:line.releasedate}) 34 | 35 | 36 | // 导入关系 actedin 电影是谁参演的 1对多 37 | LOAD CSV WITH HEADERS FROM "file:///person_to_movie.csv" AS line 38 | match (from:Person{pid:toInteger(line.pid)}),(to:Movie{mid:toInteger(line.mid)}) 39 | merge (from)-[r:actedin{pid:toInteger(line.pid),mid:toInteger(line.mid)}]->(to) 40 | 41 | //导入关系 电影是什么类型 == 1对多 42 | LOAD CSV WITH HEADERS FROM "file:///movie_to_genre.csv" AS line 43 | match (from:Movie{mid:toInteger(line.mid)}),(to:Genre{gid:toInteger(line.gid)}) 44 | merge (from)-[r:is{mid:toInteger(line.mid),gid:toInteger(line.gid)}]->(to) 45 | ``` 46 | - 问题模板 (/data/question) 47 | - hanLP的数据 (https://github.com/hankcs/HanLP/releases 中的新数据包data-for-1.7.4.zip) 48 | - 自定义词典 (/data/自定义词典.zip解压后放到hanLP的相关目录下,具体路径参考/src/main/resources/application.properties) 49 | 50 | 51 | # windows下spark环境 52 | 53 | - [https://pan.baidu.com/s/1ZIsh5yRChR0zAJXnUui4jw](https://pan.baidu.com/s/1ZIsh5yRChR0zAJXnUui4jw) 54 | 55 | # 参考 56 | - [基于电影知识图谱的智能问答系统(八) -- 终极完结篇](https://blog.csdn.net/appleyk/article/details/80422055) -------------------------------------------------------------------------------- /data/import.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlos9310/Spring-Boot-KBQA/d54107eb862b9f8c67e0f88d5fd94c88880f8457/data/import.rar -------------------------------------------------------------------------------- /data/question/question_classification.txt: -------------------------------------------------------------------------------- 1 | 0:nm 评分 2 | 1:nm 上映时间 3 | 2:nm 类型 4 | 3:nm 简介 5 | 4:nm 演员列表 6 | 5:nnt 介绍 7 | 6:nnt ng 电影作品 8 | 7:nnt 电影作品 9 | 8:nnt 参演评分 大于 x 10 | 9:nnt 参演评分 小于 x 11 | 10:nnt 电影类型 12 | 11:nnt nnr 合作 电影列表 13 | 12:nnt 电影数量 14 | 13:nnt 出生日期 -------------------------------------------------------------------------------- /data/question/vocabulary.txt: -------------------------------------------------------------------------------- 1 | 0:一 2 | 1:地区 3 | 2:谁 4 | 3:口碑 5 | 4:分 6 | 5:哪家 7 | 6:公司 8 | 7:将 9 | 8:上 10 | 9:关键人物 11 | 10:下 12 | 11:准备 13 | 12:推动 14 | 13:喜欢 15 | 14:出品 16 | 15:故事梗概 17 | 16:与 18 | 17:怎么样 19 | 18:演 20 | 19:片长 21 | 20:吗 22 | 21:相同 23 | 22:多 24 | 23:拍摄 25 | 24:影院 26 | 25:拿到 27 | 26:编剧 28 | 27:分数 29 | 28:扮演者 30 | 29:还有 31 | 30:好看 32 | 31:在 33 | 32:哪里 34 | 33:来自 35 | 34:正在 36 | 35:个 37 | 36:背景 38 | 37:成就 39 | 38:中 40 | 39:类似 41 | 40:是 42 | 41:由 43 | 42:当中 44 | 43:剧情 45 | 44:列表 46 | 45:多少 47 | 46:风格 48 | 47:这部 49 | 48:放 50 | 49:分析 51 | 50:简介 52 | 51:时长 53 | 52:重要 54 | 53:片 55 | 54:格调 56 | 55:相似 57 | 56:之中 58 | 57:豆瓣 59 | 58:线索 60 | 59:收获 61 | 60:类似于 62 | 61:情节 63 | 62:网 64 | 63:打 65 | 64:国家 66 | 65:全篇 67 | 66:奖 68 | 67:国人 69 | 68:首映 70 | 69:做 71 | 70:公司出品 72 | 71:上映 73 | 72:多久 74 | 73:这个 75 | 74:出镜率 76 | 75:赢得 77 | 76:步 78 | 77:介绍 79 | 78:扮演 80 | 79:核心人物 81 | 80:受欢迎程度 82 | 81:代表作品 83 | 82:获奖 84 | 83:差不多 85 | 84:相关 86 | 85:影响 87 | 86:未来 88 | 87:执导 89 | 88:类型 90 | 89:影评 91 | 90:计划 92 | 91:要 93 | 92:出版 94 | 93:观众 95 | 94:了 96 | 95:哪个 97 | 96:看到 98 | 97:出生于 99 | 98:制片公司 100 | 99:和 101 | 100:中演 102 | 101:演员表 103 | 102:发行 104 | 103:导演 105 | 104:接受度 106 | 105:热门 107 | 106:得 108 | 107:写 109 | 108:情况 110 | 109:多长时间 111 | 110:什么样 112 | 111:评价 113 | 112:身份 114 | 113:较高 115 | 114:度 116 | 115:生日 117 | 116:题材 118 | 117:主要 119 | 118:多长 120 | 119:放映 121 | 120:发展 122 | 121:走向 123 | 122:时间 124 | 123:讲 125 | 124:筹划 126 | 125:饰演 127 | 126:人 128 | 127:评 129 | 128:首播 130 | 129:过去 131 | 130:梗概 132 | 131:过 133 | 132:演员 134 | 133:拍 135 | 134:经典作品 136 | 135:获得 137 | 136:电影 138 | 137:评分 139 | 138:成绩 140 | 139:网上 141 | 140:票房 142 | 141:高 143 | 142:角色介绍 144 | 143:还 145 | 144:给 146 | 145:个人 147 | 146:哪一天 148 | 147:制片 149 | 148:可以 150 | 149:内容 151 | 150:出品公司 152 | 151:名字 153 | 152:剧情简介 154 | 153:人物 155 | 154:片子 156 | 155:部 157 | 156:奖项 158 | 157:故事 159 | 158:哪 160 | 159:叫 161 | 160:作品 162 | 161:制作 163 | 162:时候 164 | 163:怎么 165 | 164:角色 166 | 165:程度 167 | 166:版权 168 | 167:出生日期 169 | 168:那天 170 | 169:对 171 | 170:即将 172 | 171:出 173 | 172:属于 174 | 173:上线 175 | 174:中的 176 | 175:拿 177 | 176:大于 178 | 177:出生 179 | 178:喜剧 180 | 179:ng 181 | 180:出演 182 | 181:以上 183 | 182:以下 184 | 183:小于 185 | 184:种类 186 | 185:合作 187 | 186:一起 188 | 187:合拍 189 | 188:nnr 190 | 189:信息 -------------------------------------------------------------------------------- /data/question/【0】评分.txt: -------------------------------------------------------------------------------- 1 | nm的评分是多少 2 | nm得了多少分 3 | nm的评分有多少 4 | nm的评分 5 | nm的分数是 6 | nm电影分数是多少 7 | nm评分 8 | nm的分数是多少 9 | nm这部电影的评分是多少 -------------------------------------------------------------------------------- /data/question/【10】某演员出演过哪些类型的电影.txt: -------------------------------------------------------------------------------- 1 | nnt演过哪些风格的电影 2 | nnt演过的电影都有哪些风格 3 | nnt演过的电影有哪些类型 4 | nnt演过风格的电影 5 | nnt演过类型的电影 6 | nnt演过题材的电影 -------------------------------------------------------------------------------- /data/question/【11】演员A和演员B合作了哪些电影.txt: -------------------------------------------------------------------------------- 1 | nnt和nnr合作的电影有哪些 2 | nnt和nnr一起拍了哪些电影 3 | nnt和nnr一起演过哪些电影 4 | nnt与nnr合拍了哪些电影 5 | nnt和nnr合作了哪些电影 -------------------------------------------------------------------------------- /data/question/【12】某演员一共演过多少电影.txt: -------------------------------------------------------------------------------- 1 | nnt一共参演过多少电影 2 | nnt演过多少部电影 3 | nnt演过多少电影 4 | nnt参演的电影有多少 -------------------------------------------------------------------------------- /data/question/【13】演员出生日期.txt: -------------------------------------------------------------------------------- 1 | nnt的出生日期 2 | nnt的生日 3 | nnt生日多少 4 | nnt的出生是什么时候 5 | nnt的出生是多少 6 | nnt生日是什么时候 7 | nnt生日什么时候 8 | nnt出生日期是什么时候 9 | nnt什么时候出生的 10 | nnt出生于哪一天 11 | nnt的出生日期是哪一天 12 | nnt哪一天出生的 -------------------------------------------------------------------------------- /data/question/【1】上映.txt: -------------------------------------------------------------------------------- 1 | nm的上映时间是什么时候 2 | nm的首映时间是什么时候 3 | nm什么时候上映 4 | nm什么时候首映 5 | nm什么时候在影院上线 6 | 什么时候可以在影院看到nm 7 | nm什么时候在影院放映 8 | nm什么时候首播 9 | -------------------------------------------------------------------------------- /data/question/【2】风格.txt: -------------------------------------------------------------------------------- 1 | nm的风格是什么 2 | nm是什么风格的电影 3 | nm的格调是什么 4 | nm是什么格调的电影 5 | nm是什么类型的电影 6 | nm的类型是什么 7 | nm是什么类型的 8 | -------------------------------------------------------------------------------- /data/question/【3】剧情.txt: -------------------------------------------------------------------------------- 1 | nm的剧情是什么 2 | nm主要讲什么内容 3 | nm的主要剧情是什么 4 | nm主要讲什么故事 5 | nm的故事线索是什么 6 | nm讲了什么 7 | nm的剧情简介 8 | nm的故事内容 9 | nm的主要情节 10 | nm的情节梗概 11 | nm的故事梗概 12 | -------------------------------------------------------------------------------- /data/question/【4】某电影有哪些演员出演.txt: -------------------------------------------------------------------------------- 1 | nm有哪些演员出演 2 | nm是由哪些人演的 3 | nm中参演的演员都有哪些 4 | nm中哪些人演过 5 | nm这部电影的演员都有哪些 6 | nm这部电影中哪些人演过 -------------------------------------------------------------------------------- /data/question/【5】演员简介.txt: -------------------------------------------------------------------------------- 1 | nnt 2 | nnt 3 | nnt 4 | nnt 5 | nnt 6 | nnt是 7 | nnt是谁 8 | nnt的介绍 9 | nnt的简介 10 | 谁是nnt 11 | nnt的详细信息 12 | nnt的信息 -------------------------------------------------------------------------------- /data/question/【6】某演员出演过的类型电影有哪些.txt: -------------------------------------------------------------------------------- 1 | nnt演过哪些ng电影 2 | nnt演哪些ng电影 3 | nnt演过ng电影 4 | nnt演过什么ng电影 5 | nnt演过ng电影 6 | nnt演过的ng电影有哪些 7 | nnt出演的ng电影有哪些 -------------------------------------------------------------------------------- /data/question/【7】某演员演了什么电影.txt: -------------------------------------------------------------------------------- 1 | nnt演了什么电影 2 | nnt出演了什么电影 3 | nnt演过什么电影 4 | nnt演过哪些电影 5 | nnt过去演过哪些电影 6 | nnt以前演过哪些电影 7 | nnt演过的电影有什么 8 | nnt有哪些电影 -------------------------------------------------------------------------------- /data/question/【8】演员参演的电影评分【大于】.txt: -------------------------------------------------------------------------------- 1 | nnt参演的评分大于x的电影有哪些 2 | nnt参演的电影评分大于x的有哪些 3 | nnt参演的电影评分超过x的有哪些 4 | nnt演的电影评分超过x的有哪些 5 | nnt演的电影评分大于x的都有哪些 6 | nnt演的电影评分在x以上的都有哪些 -------------------------------------------------------------------------------- /data/question/【9】演员参演的电影评分【小于】.txt: -------------------------------------------------------------------------------- 1 | nnt参演的评分小于x的电影有哪些 2 | nnt参演的电影评分小于x的有哪些 3 | nnt参演的电影评分低于x的有哪些 4 | nnt演的电影评分低于x的有哪些 5 | nnt演的电影评分小于x的都有哪些 6 | nnt演的电影评分在x以下的都有哪些 -------------------------------------------------------------------------------- /data/自定义词典.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlos9310/Spring-Boot-KBQA/d54107eb862b9f8c67e0f88d5fd94c88880f8457/data/自定义词典.zip -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.appleyk 5 | Spring-Neo4j-Movie 6 | 0.0.1-SNAPSHOT 7 | war 8 | Spring-Boot 集成Neo4j 实现电影问答功能 9 | 10 | org.springframework.boot 11 | spring-boot-starter-parent 12 | 2.1.2.RELEASE 13 | 14 | 15 | 16 | 1.8 17 | 3.0.8 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-web 23 | 24 | 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-devtools 30 | 31 | 32 | true 33 | 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-test 38 | test 39 | 40 | 41 | 42 | junit 43 | junit 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-data-neo4j 49 | 50 | 51 | 52 | 53 | com.hankcs 54 | hanlp 55 | portable-1.7.4 56 | 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-starter-thymeleaf 61 | 62 | 63 | 64 | org.apache.spark 65 | spark-core_2.12 66 | 2.4.0 67 | 68 | 69 | org.slf4j 70 | slf4j-log4j12 71 | 72 | 73 | 74 | 75 | 76 | org.apache.spark 77 | spark-mllib_2.12 78 | 2.4.0 79 | 80 | 81 | org.codehaus.janino 82 | janino 83 | 84 | 85 | 86 | com.thoughtworks.paranamer 87 | paranamer 88 | 2.8 89 | 90 | 91 | 92 | 93 | 94 | 95 | src/main/resources 96 | 97 | **/*.properties 98 | **/*.xml 99 | **/*.html 100 | 101 | false 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /src/main/java/com/appleyk/Application.java: -------------------------------------------------------------------------------- 1 | package com.appleyk; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.builder.SpringApplicationBuilder; 6 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; 7 | 8 | @SpringBootApplication // same as @Configuration @EnableAutoConfiguration// @ComponentScan 9 | public class Application extends SpringBootServletInitializer { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(Application.class, args); 13 | } 14 | 15 | @Override 16 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 17 | return application.sources(Application.class); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/appleyk/controller/GenreController.java: -------------------------------------------------------------------------------- 1 | package com.appleyk.controller; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.PostMapping; 7 | import org.springframework.web.bind.annotation.RequestBody; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RequestParam; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | import com.appleyk.node.Genre; 13 | import com.appleyk.repository.GenreRepository; 14 | import com.appleyk.result.ResponseMessage; 15 | import com.appleyk.result.ResponseResult; 16 | 17 | @RestController 18 | @RequestMapping("/rest/appleyk/genre") 19 | public class GenreController { 20 | 21 | @Autowired 22 | GenreRepository genreRepository; 23 | 24 | 25 | /** 26 | * 根据类型名查询Genre实体 27 | * @param title 28 | * @return 29 | */ 30 | @RequestMapping("/get") 31 | public List getGenres(@RequestParam(value="name") String name){ 32 | return genreRepository.findByName(name); 33 | } 34 | 35 | /** 36 | * 创建一个电影类型节点 37 | * @param genre 38 | * @return 39 | */ 40 | @PostMapping("/save") 41 | public ResponseResult saveGenre(@RequestBody Genre genre){ 42 | genreRepository.save(genre); 43 | return new ResponseResult(ResponseMessage.OK); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/appleyk/controller/MovieController.java: -------------------------------------------------------------------------------- 1 | package com.appleyk.controller; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.PostMapping; 7 | import org.springframework.web.bind.annotation.RequestBody; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RequestParam; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | import com.appleyk.node.Movie; 13 | import com.appleyk.repository.MovieRepository; 14 | import com.appleyk.result.ResponseMessage; 15 | import com.appleyk.result.ResponseResult; 16 | import com.appleyk.result.ResultData; 17 | 18 | @RestController 19 | @RequestMapping("/rest/appleyk/movie") //restful风格的api接口 20 | public class MovieController { 21 | 22 | @Autowired 23 | MovieRepository movieRepository; 24 | 25 | /** 26 | * 根据电影名查询电影实体 27 | * @param title 28 | * @return 29 | */ 30 | @RequestMapping("/get") 31 | public List getMovies(@RequestParam(value="title") String title){ 32 | return movieRepository.findByTitle(title); 33 | } 34 | 35 | /** 36 | * 创建一个电影节点 37 | * @param genre 38 | * @return 39 | */ 40 | @PostMapping("/save") 41 | public ResponseResult saveMovie(@RequestBody Movie movie){ 42 | movieRepository.save(movie); 43 | return new ResponseResult(ResponseMessage.OK); 44 | } 45 | 46 | 47 | @RequestMapping("/query") 48 | public ResponseResult queryMovieTiles(){ 49 | List movieTiles = movieRepository.getMovieTiles(); 50 | ResultData result = new ResultData(ResponseMessage.OK, movieTiles); 51 | return new ResponseResult(result); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/appleyk/controller/PageIndexController.java: -------------------------------------------------------------------------------- 1 | package com.appleyk.controller; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | 6 | @Controller 7 | public class PageIndexController { 8 | 9 | @RequestMapping("/") 10 | public String index() { 11 | return "index"; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/appleyk/controller/PersonController.java: -------------------------------------------------------------------------------- 1 | package com.appleyk.controller; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.PostMapping; 7 | import org.springframework.web.bind.annotation.RequestBody; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RequestParam; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | import com.appleyk.node.Person; 13 | import com.appleyk.repository.PersonRepository; 14 | import com.appleyk.result.ResponseMessage; 15 | import com.appleyk.result.ResponseResult; 16 | 17 | @RestController 18 | @RequestMapping("/rest/appleyk/person") 19 | public class PersonController { 20 | 21 | @Autowired 22 | PersonRepository personRepository; 23 | 24 | /** 25 | * 根据演员名查询Person实体 26 | * 27 | * @param title 28 | * @return 29 | */ 30 | @RequestMapping("/get") 31 | public List getPersons(@RequestParam(value = "name") String name) { 32 | return personRepository.findByName(name); 33 | } 34 | 35 | /** 36 | * 创建一个演员节点 37 | * 38 | * @param genre 39 | * @return 40 | */ 41 | @PostMapping("/save") 42 | public ResponseResult savePerson(@RequestBody Person person) { 43 | personRepository.save(person); 44 | return new ResponseResult(ResponseMessage.OK); 45 | } 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/appleyk/controller/QuestionController.java: -------------------------------------------------------------------------------- 1 | package com.appleyk.controller; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RequestParam; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | import com.appleyk.service.QuestionService; 9 | 10 | @RestController 11 | @RequestMapping("/rest/appleyk/question") 12 | public class QuestionController { 13 | 14 | @Autowired 15 | QuestionService questService; 16 | 17 | @RequestMapping("/query") 18 | public String query(@RequestParam(value = "question") String question) throws Exception { 19 | return questService.answer(question); 20 | } 21 | 22 | @RequestMapping("/path") 23 | public void checkPath(){ 24 | questService.showDictPath(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/appleyk/node/BaseEntity.java: -------------------------------------------------------------------------------- 1 | package com.appleyk.node; 2 | 3 | import org.neo4j.ogm.annotation.Id; 4 | import com.fasterxml.jackson.annotation.JsonIdentityInfo; 5 | import com.fasterxml.jackson.annotation.ObjectIdGenerators; 6 | 7 | /** 8 | * 抽取共同的属性字段 9 | */ 10 | @JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id") 11 | public abstract class BaseEntity { 12 | 13 | /** 14 | * Neo4j会分配的ID(节点唯一标识 当前类中有效) 15 | */ 16 | @Id 17 | private Long id; 18 | public Long getId() { 19 | return id; 20 | } 21 | 22 | public void setId(Long id) { 23 | this.id = id; 24 | } 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/appleyk/node/Genre.java: -------------------------------------------------------------------------------- 1 | package com.appleyk.node; 2 | 3 | import org.neo4j.ogm.annotation.NodeEntity; 4 | 5 | @NodeEntity 6 | public class Genre extends BaseEntity{ 7 | 8 | 9 | private Long gid; 10 | private String name; 11 | 12 | public Genre(){ 13 | 14 | } 15 | 16 | public Long getGid() { 17 | return gid; 18 | } 19 | 20 | public void setGid(Long gid) { 21 | this.gid = gid; 22 | } 23 | 24 | public String getName() { 25 | return name; 26 | } 27 | 28 | public void setName(String name) { 29 | this.name = name; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/appleyk/node/Movie.java: -------------------------------------------------------------------------------- 1 | package com.appleyk.node; 2 | 3 | import java.util.List; 4 | 5 | import org.neo4j.ogm.annotation.NodeEntity; 6 | import org.neo4j.ogm.annotation.Relationship; 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty; 9 | 10 | @NodeEntity 11 | public class Movie extends BaseEntity{ 12 | 13 | private Long mid; 14 | private Double rating; 15 | private String releasedate; 16 | private String title; 17 | private String introduction; 18 | 19 | @Relationship(type = "is") 20 | @JsonProperty("电影类型") 21 | private List genres; 22 | 23 | 24 | public Movie() { 25 | 26 | } 27 | 28 | public Long getMid() { 29 | return mid; 30 | } 31 | 32 | public void setMid(Long mid) { 33 | this.mid = mid; 34 | } 35 | 36 | public Double getRating() { 37 | return rating; 38 | } 39 | 40 | public void setRating(Double rating) { 41 | this.rating = rating; 42 | } 43 | 44 | public String getReleasedate() { 45 | return releasedate; 46 | } 47 | 48 | public void setReleasedate(String releasedate) { 49 | this.releasedate = releasedate; 50 | } 51 | 52 | public String getTitle() { 53 | return title; 54 | } 55 | 56 | public void setTitle(String title) { 57 | this.title = title; 58 | } 59 | 60 | public String getIntroduction() { 61 | return introduction; 62 | } 63 | 64 | public void setIntroduction(String introduction) { 65 | this.introduction = introduction; 66 | } 67 | 68 | public List getGenres() { 69 | return genres; 70 | } 71 | 72 | public void setGenres(List genres) { 73 | this.genres = genres; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/appleyk/node/Person.java: -------------------------------------------------------------------------------- 1 | package com.appleyk.node; 2 | 3 | import java.util.List; 4 | 5 | import org.neo4j.ogm.annotation.NodeEntity; 6 | import org.neo4j.ogm.annotation.Relationship; 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty; 9 | 10 | @NodeEntity 11 | public class Person extends BaseEntity { 12 | 13 | private Long pid; 14 | private String name; 15 | private String birth; 16 | private String birthplace; 17 | private String death; 18 | private String biography; 19 | 20 | @Relationship(type = "actedin") 21 | @JsonProperty("参演电影") 22 | private List movies; 23 | 24 | public Person(){ 25 | 26 | } 27 | 28 | public Long getPid() { 29 | return pid; 30 | } 31 | 32 | public void setPid(Long pid) { 33 | this.pid = pid; 34 | } 35 | 36 | public String getName() { 37 | return name; 38 | } 39 | 40 | public void setName(String name) { 41 | this.name = name; 42 | } 43 | 44 | public String getBirth() { 45 | return birth; 46 | } 47 | 48 | public void setBirth(String birth) { 49 | this.birth = birth; 50 | } 51 | 52 | public String getBirthplace() { 53 | return birthplace; 54 | } 55 | 56 | public void setBirthplace(String birthplace) { 57 | this.birthplace = birthplace; 58 | } 59 | 60 | public String getDeath() { 61 | return death; 62 | } 63 | 64 | public void setDeath(String death) { 65 | this.death = death; 66 | } 67 | 68 | public String getBiography() { 69 | return biography; 70 | } 71 | 72 | public void setBiography(String biography) { 73 | this.biography = biography; 74 | } 75 | 76 | public List getMovies() { 77 | return movies; 78 | } 79 | 80 | public void setMovies(List movies) { 81 | this.movies = movies; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/appleyk/process/ModelProcess.java: -------------------------------------------------------------------------------- 1 | package com.appleyk.process; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileReader; 7 | import java.io.IOException; 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | import java.util.LinkedList; 11 | import java.util.List; 12 | import java.util.Map; 13 | import java.util.Set; 14 | 15 | import org.apache.spark.SparkConf; 16 | import org.apache.spark.api.java.JavaRDD; 17 | import org.apache.spark.api.java.JavaSparkContext; 18 | import org.apache.spark.mllib.classification.NaiveBayes; 19 | import org.apache.spark.mllib.classification.NaiveBayesModel; 20 | import org.apache.spark.mllib.linalg.Vector; 21 | import org.apache.spark.mllib.linalg.Vectors; 22 | import org.apache.spark.mllib.regression.LabeledPoint; 23 | 24 | import com.hankcs.hanlp.HanLP; 25 | import com.hankcs.hanlp.seg.Segment; 26 | import com.hankcs.hanlp.seg.common.Term; 27 | 28 | /** 29 | * Spark贝叶斯分类器 + HanLP分词器 + 实现问题语句的抽象+模板匹配+关键性语句还原 30 | * @blob http://blog.csdn.net/appleyk 31 | * @date 2018年5月9日-上午10:07:52 32 | */ 33 | public class ModelProcess { 34 | 35 | 36 | /** 37 | * 分类标签号和问句模板对应表 38 | */ 39 | Map questionsPattern; 40 | 41 | /** 42 | * Spark贝叶斯分类器 43 | */ 44 | NaiveBayesModel nbModel; 45 | 46 | /** 47 | * 词语和下标的对应表 == 词汇表 48 | */ 49 | Map vocabulary; 50 | 51 | /** 52 | * 关键字与其词性的map键值对集合 == 句子抽象 53 | */ 54 | Map abstractMap; 55 | 56 | /** 57 | * 指定问题question及字典的txt模板所在的根目录 58 | */ 59 | String rootDirPath = "D:/HanLP/data"; 60 | 61 | /** 62 | * 分类模板索引 63 | */ 64 | int modelIndex = 0; 65 | 66 | public ModelProcess() throws Exception{ 67 | questionsPattern = loadQuestionsPattern(); 68 | vocabulary = loadVocabulary(); 69 | nbModel = loadClassifierModel(); 70 | } 71 | 72 | 73 | public ModelProcess(String rootDirPath) throws Exception{ 74 | this.rootDirPath = rootDirPath+'/'; 75 | questionsPattern = loadQuestionsPattern(); 76 | vocabulary = loadVocabulary(); 77 | nbModel = loadClassifierModel(); 78 | } 79 | 80 | public ArrayList analyQuery(String queryString) throws Exception { 81 | 82 | /** 83 | * 打印问句 84 | */ 85 | System.out.println("原始句子:"+queryString); 86 | System.out.println("========HanLP开始分词========"); 87 | 88 | /** 89 | * 抽象句子,利用HanPL分词,将关键字进行词性抽象 90 | */ 91 | String abstr = queryAbstract(queryString); 92 | System.out.println("句子抽象化结果:"+abstr);// nm 的 导演 是 谁 93 | 94 | /** 95 | * 将抽象的句子与spark训练集中的模板进行匹配,拿到句子对应的模板 96 | */ 97 | String strPatt = queryClassify(abstr); 98 | System.out.println("句子套用模板结果:"+strPatt); // nm 制作 导演列表 99 | 100 | 101 | /** 102 | * 模板还原成句子,此时问题已转换为我们熟悉的操作 103 | */ 104 | String finalPattern = queryExtenstion(strPatt); 105 | System.out.println("原始句子替换成系统可识别的结果:"+finalPattern);// 但丁密码 制作 导演列表 106 | 107 | 108 | ArrayList resultList = new ArrayList(); 109 | resultList.add(String.valueOf(modelIndex)); 110 | String[] finalPattArray = finalPattern.split(" "); 111 | for (String word : finalPattArray) 112 | resultList.add(word); 113 | return resultList; 114 | } 115 | 116 | public String queryAbstract(String querySentence) { 117 | 118 | // 句子抽象化 119 | Segment segment = HanLP.newSegment().enableCustomDictionary(true); 120 | List terms = segment.seg(querySentence); 121 | String abstractQuery = ""; 122 | abstractMap = new HashMap(); 123 | int nrCount = 0; //nr 人名词性这个 词语出现的频率 124 | for (Term term : terms) { 125 | String word = term.word; 126 | String termStr = term.toString(); 127 | System.out.println(termStr); 128 | if (termStr.contains("nm")) { //nm 电影名 129 | abstractQuery += "nm "; 130 | abstractMap.put("nm", word); 131 | } else if (termStr.contains("nr") && nrCount == 0) { //nr 人名 132 | abstractQuery += "nnt "; 133 | abstractMap.put("nnt", word); 134 | nrCount++; 135 | }else if (termStr.contains("nr") && nrCount == 1) { //nr 人名 再出现一次,改成nnr 136 | abstractQuery += "nnr "; 137 | abstractMap.put("nnr", word); 138 | nrCount++; 139 | }else if (termStr.contains("x")) { //x 评分 140 | abstractQuery += "x "; 141 | abstractMap.put("x", word); 142 | } else if (termStr.contains("ng")) { //ng 类型 143 | abstractQuery += "ng "; 144 | abstractMap.put("ng", word); 145 | } 146 | else { 147 | abstractQuery += word + " "; 148 | } 149 | } 150 | System.out.println("========HanLP分词结束========"); 151 | return abstractQuery; 152 | } 153 | 154 | public String queryExtenstion(String queryPattern) { 155 | // 句子还原 156 | Set set = abstractMap.keySet(); 157 | for (String key : set) { 158 | /** 159 | * 如果句子模板中含有抽象的词性 160 | */ 161 | if (queryPattern.contains(key)) { 162 | 163 | /** 164 | * 则替换抽象词性为具体的值 165 | */ 166 | String value = abstractMap.get(key); 167 | queryPattern = queryPattern.replace(key, value); 168 | } 169 | } 170 | String extendedQuery = queryPattern; 171 | /** 172 | * 当前句子处理完,抽象map清空释放空间并置空,等待下一个句子的处理 173 | */ 174 | abstractMap.clear(); 175 | abstractMap = null; 176 | return extendedQuery; 177 | } 178 | 179 | 180 | /** 181 | * 加载词汇表 == 关键特征 == 与HanLP分词后的单词进行匹配 182 | * @return 183 | */ 184 | public Map loadVocabulary() { 185 | Map vocabulary = new HashMap(); 186 | File file = new File(rootDirPath + "question/vocabulary.txt"); 187 | BufferedReader br = null; 188 | try { 189 | br = new BufferedReader(new FileReader(file)); 190 | } catch (FileNotFoundException e) { 191 | e.printStackTrace(); 192 | } 193 | String line; 194 | try { 195 | while ((line = br.readLine()) != null) { 196 | String[] tokens = line.split(":"); 197 | int index = Integer.parseInt(tokens[0]); 198 | String word = tokens[1]; 199 | vocabulary.put(word, index); 200 | } 201 | } catch (NumberFormatException e) { 202 | e.printStackTrace(); 203 | } catch (IOException e) { 204 | e.printStackTrace(); 205 | } 206 | return vocabulary; 207 | } 208 | 209 | /** 210 | * 加载文件,并读取内容返回 211 | * @param filename 212 | * @return 213 | * @throws IOException 214 | */ 215 | public String loadFile(String filename) throws IOException { 216 | File file = new File(rootDirPath + filename); 217 | BufferedReader br = new BufferedReader(new FileReader(file)); 218 | String content = ""; 219 | String line; 220 | while ((line = br.readLine()) != null) { 221 | /** 222 | * 文本的换行符暂定用"`"代替 223 | */ 224 | content += line + "`"; 225 | } 226 | /** 227 | * 关闭资源 228 | */ 229 | br.close(); 230 | return content; 231 | } 232 | 233 | /** 234 | * 句子分词后与词汇表进行key匹配转换为double向量数组 235 | * @param sentence 236 | * @return 237 | * @throws Exception 238 | */ 239 | public double[] sentenceToArrays(String sentence) throws Exception { 240 | 241 | double[] vector = new double[vocabulary.size()]; 242 | /** 243 | * 模板对照词汇表的大小进行初始化,全部为0.0 244 | */ 245 | for (int i = 0; i < vocabulary.size(); i++) { 246 | vector[i] = 0; 247 | } 248 | 249 | /** 250 | * HanLP分词,拿分词的结果和词汇表里面的关键特征进行匹配 251 | */ 252 | Segment segment = HanLP.newSegment(); 253 | List terms = segment.seg(sentence); 254 | for (Term term : terms) { 255 | String word = term.word; 256 | /** 257 | * 如果命中,0.0 改为 1.0 258 | */ 259 | if (vocabulary.containsKey(word)) { 260 | int index = vocabulary.get(word); 261 | vector[index] = 1; 262 | } 263 | } 264 | return vector; 265 | } 266 | 267 | /** 268 | * Spark朴素贝叶斯(naiveBayes) 269 | * 对特定的模板进行加载并分类 270 | * 欲了解Spark朴素贝叶斯,可参考地址:https://blog.csdn.net/appleyk/article/details/80348912 271 | * @return 272 | * @throws Exception 273 | */ 274 | public NaiveBayesModel loadClassifierModel() throws Exception { 275 | 276 | /** 277 | * 生成Spark对象 278 | * 一、Spark程序是通过SparkContext发布到Spark集群的 279 | * Spark程序的运行都是在SparkContext为核心的调度器的指挥下进行的 280 | * Spark程序的结束是以SparkContext结束作为结束 281 | * JavaSparkContext对象用来创建Spark的核心RDD的 282 | * 注意:第一个RDD,一定是由SparkContext来创建的 283 | * 284 | * 二、SparkContext的主构造器参数为 SparkConf 285 | * SparkConf必须设置appname和master,否则会报错 286 | * spark.master 用于设置部署模式 287 | * local[*] == 本地运行模式[也可以是集群的形式],如果需要多个线程执行,可以设置为local[2],表示2个线程 ,*表示多个 288 | * spark.app.name 用于指定应用的程序名称 == 289 | */ 290 | 291 | /** 292 | * 题外话 293 | * 贝叶斯是谁? 294 | * 贝叶斯(约1701-1763) Thomas Bayes,英国数学家。 295 | * 1702年出生于伦敦,做过神甫。 296 | * 1742年成为英国皇家学会会员。 297 | * 1763年4月7日逝世。 298 | * 贝叶斯在数学方面主要研究概率论 == 贝叶斯公式是概率论中较为重要的公式 299 | */ 300 | SparkConf conf = new SparkConf().setAppName("NaiveBayesTest").setMaster("local[*]"); 301 | JavaSparkContext sc = new JavaSparkContext(conf); 302 | 303 | /** 304 | * 训练集生成 305 | * labeled point 是一个局部向量,要么是密集型的要么是稀疏型的 306 | * 用一个label/response进行关联。在MLlib里,labeled points 被用来监督学习算法 307 | * 我们使用一个double数来存储一个label,因此我们能够使用labeled points进行回归和分类 308 | */ 309 | List train_list = new LinkedList(); 310 | String[] sentences = null; 311 | 312 | 313 | /** 314 | * 英雄的评分是多少 315 | */ 316 | String scoreQuestions = loadFile("question/【0】评分.txt"); 317 | sentences = scoreQuestions.split("`"); 318 | for (String sentence : sentences) { 319 | double[] array = sentenceToArrays(sentence); 320 | LabeledPoint train_one = new LabeledPoint(0.0, Vectors.dense(array)); 321 | train_list.add(train_one); 322 | } 323 | 324 | /** 325 | * 英雄什么时候上映的 326 | */ 327 | String timeQuestions = loadFile("question/【1】上映.txt"); 328 | sentences = timeQuestions.split("`"); 329 | for (String sentence : sentences) { 330 | double[] array = sentenceToArrays(sentence); 331 | LabeledPoint train_one = new LabeledPoint(1.0, Vectors.dense(array)); 332 | train_list.add(train_one); 333 | } 334 | 335 | 336 | /** 337 | * 英雄是什么类型的 338 | */ 339 | String styleQuestions = loadFile("question/【2】风格.txt"); 340 | sentences = styleQuestions.split("`"); 341 | for (String sentence : sentences) { 342 | double[] array = sentenceToArrays(sentence); 343 | LabeledPoint train_one = new LabeledPoint(2.0, Vectors.dense(array)); 344 | train_list.add(train_one); 345 | } 346 | 347 | 348 | /** 349 | * 英雄的简介、英雄的剧情是什么 350 | */ 351 | String storyQuestions = loadFile("question/【3】剧情.txt"); 352 | sentences = storyQuestions.split("`"); 353 | for (String sentence : sentences) { 354 | double[] array = sentenceToArrays(sentence); 355 | LabeledPoint train_one = new LabeledPoint(3.0, Vectors.dense(array)); 356 | train_list.add(train_one); 357 | } 358 | 359 | /** 360 | * 英雄有哪些演员出演、出演英雄的演员都有哪些 361 | */ 362 | String actorsQuestion = loadFile("question/【4】某电影有哪些演员出演.txt"); 363 | sentences = actorsQuestion.split("`"); 364 | for (String sentence : sentences) { 365 | double[] array = sentenceToArrays(sentence); 366 | LabeledPoint train_one = new LabeledPoint(4.0, Vectors.dense(array)); 367 | train_list.add(train_one); 368 | } 369 | 370 | 371 | /** 372 | * 章子怡 373 | */ 374 | String actorInfos = loadFile("question/【5】演员简介.txt"); 375 | sentences = actorInfos.split("`"); 376 | for (String sentence : sentences) { 377 | double[] array = sentenceToArrays(sentence); 378 | LabeledPoint train_one = new LabeledPoint(5.0, Vectors.dense(array)); 379 | train_list.add(train_one); 380 | } 381 | 382 | /** 383 | * 周星驰出演的科幻类型的电影有哪些 384 | */ 385 | String genreMovies = loadFile("question/【6】某演员出演过的类型电影有哪些.txt"); 386 | sentences = genreMovies.split("`"); 387 | for (String sentence : sentences) { 388 | double[] array = sentenceToArrays(sentence); 389 | LabeledPoint train_one = new LabeledPoint(6.0, Vectors.dense(array)); 390 | train_list.add(train_one); 391 | } 392 | 393 | 394 | /** 395 | * 周星驰演了哪些电影 396 | */ 397 | String actorsMovie = loadFile("question/【7】某演员演了什么电影.txt"); 398 | sentences = actorsMovie.split("`"); 399 | for (String sentence : sentences) { 400 | double[] array = sentenceToArrays(sentence); 401 | LabeledPoint train_one = new LabeledPoint(7.0, Vectors.dense(array)); 402 | train_list.add(train_one); 403 | } 404 | 405 | /** 406 | * 巩俐参演的电影评分在8.5分以上的有哪些、巩俐参演的电影评分大于8.5分的有哪些 407 | */ 408 | String highScoreMovies = loadFile("question/【8】演员参演的电影评分【大于】.txt"); 409 | sentences = highScoreMovies.split("`"); 410 | for (String sentence : sentences) { 411 | double[] array = sentenceToArrays(sentence); 412 | LabeledPoint train_one = new LabeledPoint(8.0, Vectors.dense(array)); 413 | train_list.add(train_one); 414 | } 415 | 416 | 417 | /** 418 | * 巩俐参演的电影评分在8.5分以下的有哪些、巩俐参演的电影评分小于8.5分的有哪些 419 | */ 420 | String lowScoreMovies = loadFile("question/【9】演员参演的电影评分【小于】.txt"); 421 | sentences = lowScoreMovies.split("`"); 422 | for (String sentence : sentences) { 423 | double[] array = sentenceToArrays(sentence); 424 | LabeledPoint train_one = new LabeledPoint(9.0, Vectors.dense(array)); 425 | train_list.add(train_one); 426 | } 427 | 428 | 429 | /** 430 | * 章子怡演过哪些类型的电影 431 | */ 432 | String actorMovieGenres = loadFile("question/【10】某演员出演过哪些类型的电影.txt"); 433 | sentences = actorMovieGenres.split("`"); 434 | for (String sentence : sentences) { 435 | double[] array = sentenceToArrays(sentence); 436 | LabeledPoint train_one = new LabeledPoint(10.0, Vectors.dense(array)); 437 | train_list.add(train_one); 438 | } 439 | 440 | /** 441 | * 章子怡与李连杰合作过哪些电影、章子怡和巩俐一起演过什么电影 442 | */ 443 | String withMovies = loadFile("question/【11】演员A和演员B合作了哪些电影.txt"); 444 | sentences = withMovies.split("`"); 445 | for (String sentence : sentences) { 446 | double[] array = sentenceToArrays(sentence); 447 | LabeledPoint train_one = new LabeledPoint(11.0, Vectors.dense(array)); 448 | train_list.add(train_one); 449 | } 450 | 451 | 452 | /** 453 | * 章子怡与李连杰合作过哪些电影、章子怡和巩俐一起演过什么电影 454 | */ 455 | String countMovies = loadFile("question/【12】某演员一共演过多少电影.txt"); 456 | sentences = countMovies.split("`"); 457 | for (String sentence : sentences) { 458 | double[] array = sentenceToArrays(sentence); 459 | LabeledPoint train_one = new LabeledPoint(12.0, Vectors.dense(array)); 460 | train_list.add(train_one); 461 | } 462 | 463 | 464 | /** 465 | * 章子怡的生日是多少、章子怡的出生日期是什么时候 466 | */ 467 | String actorBirthdayQuestion = loadFile("question/【13】演员出生日期.txt"); 468 | sentences = actorBirthdayQuestion.split("`"); 469 | for (String sentence : sentences) { 470 | double[] array = sentenceToArrays(sentence); 471 | LabeledPoint train_one = new LabeledPoint(13.0, Vectors.dense(array)); 472 | train_list.add(train_one); 473 | } 474 | 475 | /** 476 | * SPARK的核心是RDD(弹性分布式数据集) 477 | * Spark是Scala写的,JavaRDD就是Spark为Java写的一套API 478 | * JavaSparkContext sc = new JavaSparkContext(sparkConf); //对应JavaRDD 479 | * SparkContext sc = new SparkContext(sparkConf) ; //对应RDD 480 | */ 481 | JavaRDD trainingRDD = sc.parallelize(train_list); 482 | NaiveBayesModel nb_model = NaiveBayes.train(trainingRDD.rdd()); 483 | 484 | /** 485 | * 记得关闭资源 486 | */ 487 | sc.close(); 488 | 489 | /** 490 | * 返回贝叶斯分类器 491 | */ 492 | return nb_model; 493 | 494 | } 495 | 496 | /** 497 | * 加载问题模板 == 分类器标签 498 | * @return 499 | */ 500 | public Map loadQuestionsPattern() { 501 | Map questionsPattern = new HashMap(); 502 | File file = new File(rootDirPath + "question/question_classification.txt"); 503 | BufferedReader br = null; 504 | try { 505 | br = new BufferedReader(new FileReader(file)); 506 | } catch (FileNotFoundException e1) { 507 | e1.printStackTrace(); 508 | } 509 | String line; 510 | try { 511 | while ((line = br.readLine()) != null) { 512 | String[] tokens = line.split(":"); 513 | double index = Double.valueOf(tokens[0]); 514 | String pattern = tokens[1]; 515 | questionsPattern.put(index, pattern); 516 | } 517 | } catch (NumberFormatException e) { 518 | e.printStackTrace(); 519 | } catch (IOException e) { 520 | e.printStackTrace(); 521 | } 522 | return questionsPattern; 523 | } 524 | 525 | /** 526 | * 贝叶斯分类器分类的结果,拿到匹配的分类标签号,并根据标签号返回问题的模板 527 | * @param sentence 528 | * @return 529 | * @throws Exception 530 | */ 531 | public String queryClassify(String sentence) throws Exception { 532 | 533 | double[] testArray = sentenceToArrays(sentence); 534 | Vector v = Vectors.dense(testArray); 535 | 536 | /** 537 | * 对数据进行预测predict 538 | * 句子模板在 spark贝叶斯分类器中的索引【位置】 539 | * 根据词汇使用的频率推断出句子对应哪一个模板 540 | */ 541 | double index = nbModel.predict(v); 542 | modelIndex = (int)index; 543 | System.out.println("the model index is " + index); 544 | // Vector vRes = nbModel.predictProbabilities(v); 545 | // System.out.println("问题模板分类【0】概率:"+vRes.toArray()[0]); 546 | // System.out.println("问题模板分类【13】概率:"+vRes.toArray()[13]); 547 | return questionsPattern.get(index); 548 | } 549 | 550 | public static void main(String[] agrs) throws Exception { 551 | System.out.println("Hello World !"); 552 | } 553 | } 554 | -------------------------------------------------------------------------------- /src/main/java/com/appleyk/repository/GenreRepository.java: -------------------------------------------------------------------------------- 1 | package com.appleyk.repository; 2 | 3 | import com.appleyk.node.Genre; 4 | import org.springframework.data.neo4j.annotation.Query; 5 | import org.springframework.data.neo4j.repository.Neo4jRepository; 6 | import org.springframework.data.repository.query.Param; 7 | 8 | import java.util.List; 9 | 10 | public interface GenreRepository extends Neo4jRepository{ 11 | 12 | @Query("MATCH (n:Genre) where n.name='日本AV' return n") 13 | List getGenres(@Param("name") String name); 14 | 15 | List findByName(@Param("name") String name); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/appleyk/repository/MovieRepository.java: -------------------------------------------------------------------------------- 1 | package com.appleyk.repository; 2 | 3 | import com.appleyk.node.Movie; 4 | import org.springframework.data.neo4j.annotation.Query; 5 | import org.springframework.data.neo4j.repository.Neo4jRepository; 6 | import org.springframework.data.repository.query.Param; 7 | 8 | import java.util.List; 9 | 10 | public interface MovieRepository extends Neo4jRepository{ 11 | 12 | List findByTitle(@Param("title") String title); 13 | @Query("match(n:Person)-[:actedin]->(m:Movie) where n.name='章子怡' return m.title") 14 | List getMovieTiles(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/appleyk/repository/PersonRepository.java: -------------------------------------------------------------------------------- 1 | package com.appleyk.repository; 2 | 3 | import com.appleyk.node.Person; 4 | import org.springframework.data.neo4j.repository.Neo4jRepository; 5 | import org.springframework.data.repository.query.Param; 6 | 7 | import java.util.List; 8 | 9 | public interface PersonRepository extends Neo4jRepository{ 10 | List findByName(@Param("name") String name); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/appleyk/repository/QuestionRepository.java: -------------------------------------------------------------------------------- 1 | package com.appleyk.repository; 2 | 3 | import com.appleyk.node.Movie; 4 | import org.springframework.data.neo4j.annotation.Query; 5 | import org.springframework.data.neo4j.repository.Neo4jRepository; 6 | import org.springframework.data.repository.query.Param; 7 | 8 | import java.util.List; 9 | 10 | 11 | /** 12 | * 基于电影知识图谱的自问自答的查询接口 13 | * @author yukun24@126.com 14 | * @blob http://blog.csdn.net/appleyk 15 | * @date 2018年5月10日-下午3:48:51 16 | */ 17 | public interface QuestionRepository extends Neo4jRepository { 18 | 19 | /** 20 | * 0 对应问题模板0 == nm(电影) 评分 21 | * 22 | * @param title 23 | * 电影标题 24 | * @return 返回电影的评分 25 | */ 26 | @Query("match(n:Movie) where n.title={title} return n.rating") 27 | Double getMovieRating(@Param("title") String title); 28 | 29 | /** 30 | * 1 对应问题模板1 == nm(电影) 上映时间 31 | * 32 | * @param title 33 | * 电影标题 34 | * @return 返回电影的上映日期 35 | */ 36 | @Query("match(n:Movie) where n.title={title} return n.releasedate") 37 | String getMovieReleaseDate(@Param("title") String title); 38 | 39 | /** 40 | * 2 对应问题模板2 == nm(电影) 类型 41 | * 42 | * @param title 43 | * 电影标题 44 | * @return 返回电影的类型、风格 45 | */ 46 | @Query("match(n:Movie)-[r:is]->(b:Genre) where n.title={title} return b.name") 47 | List getMovieTypes(@Param("title") String title); 48 | 49 | /** 50 | * 3 对应问题模板3 == nm(电影) 简介 51 | * 52 | * @param title 53 | * 电影标题 54 | * @return 返回电影的剧情、简介 55 | */ 56 | @Query("match(n:Movie) where n.title ={title} return n.introduction") 57 | String getMovieInfo(@Param("title") String title); 58 | 59 | /** 60 | * 4 对应问题模板4 == nm(电影) 简介 61 | * 62 | * @param title 63 | * 电影标题 64 | * @return 返回电影中出演的演员都有哪些 65 | */ 66 | @Query("match(n:Person)-[:actedin]-(m:Movie) where m.title ={title} return n.name") 67 | List getMovieActors(@Param("title") String title); 68 | 69 | /** 70 | * 5 对应问题模板5 == nnt(演员) 简介 71 | * 72 | * @param name 73 | * 演员名 74 | * @return 返回演员的出生日期 75 | */ 76 | @Query("match(n:Person) where n.name={name} return n.birthplace") 77 | String getActorInfo(@Param("name") String name); 78 | 79 | /** 80 | * 6 对应问题模板6 == nnt(演员) ng(电影类型) 电影作品 81 | * 82 | * @param name 83 | * 演员名 84 | * @param gname 85 | * 电影类型名称 86 | * @return 返回电影名称列表 87 | */ 88 | @Query("match(n:Person)-[:actedin]-(m:Movie) where n.name ={name} " 89 | + "match(g:Genre)-[:is]-(m) where g.name=~{gname} return distinct m.title") 90 | List getActorMoviesByType(@Param("name") String name, @Param("gname") String gname); 91 | 92 | /** 93 | * 7对应问题模板7 == nnt(演员) 电影作品 94 | * 95 | * @param name 96 | * @return 97 | */ 98 | @Query("match(n:Person)-[:actedin]->(m:Movie) where n.name={name} return m.title") 99 | List getActorMovies(@Param("name") String name); 100 | 101 | /** 102 | * 8对应问题模板8 == nnt 参演评分 大于 x(电影评分) 103 | * 104 | * @param name 演员姓名 105 | * @param score 电影分数 106 | * @return 107 | */ 108 | @Query("match(n:Person)-[:actedin]-(m:Movie) where n.name ={name} and m.rating > {score} return m.title") 109 | List getActorMoviesByHScore(@Param("name") String name,@Param("score") Double score); 110 | 111 | 112 | /** 113 | * 9对应问题模板9 == nnt 参演评分 小于 x(电影评分) 114 | * 115 | * @param name 演员姓名 116 | * @param score 电影分数 117 | * @return 118 | */ 119 | @Query("match(n:Person)-[:actedin]-(m:Movie) where n.name ={name} and m.rating < {score} return m.title") 120 | List getActorMoviesByLScore(@Param("name") String name,@Param("score") Double score); 121 | 122 | 123 | /** 124 | * 10 对应问题模板10 == nnt(演员) 电影类型 125 | * 126 | * @param name 127 | * 演员名 128 | * @return 返回演员出演过的所有电影的类型集合【不重复的】 129 | */ 130 | @Query("match(n:Person)-[:actedin]-(m:Movie) where n.name ={name} " 131 | + "match(p:Genre)-[:is]-(m) return distinct p.name") 132 | List getActorMoviesType(@Param("name") String name); 133 | 134 | 135 | /** 136 | * 12 对应问题模板12 == nnt(演员) 电影数量 137 | * 138 | * @param name 139 | * 演员名 140 | * @return 返回演员出演过的所有电影的类型集合【不重复的】 141 | */ 142 | @Query("match(n)-[:actedin]-(m) where n.name ={name} return count(*)") 143 | Integer getMoviesCount(@Param("name") String name); 144 | 145 | /** 146 | * 13 对应问题模板13 == nnt(演员) 出生日期 147 | * 148 | * @param name 149 | * 演员名 150 | * @return 返回演员的出生日期 151 | */ 152 | @Query("match(n:Person) where n.name={name} return n.birth") 153 | String getActorBirth(@Param("name") String name); 154 | 155 | } 156 | -------------------------------------------------------------------------------- /src/main/java/com/appleyk/result/ResponseMessage.java: -------------------------------------------------------------------------------- 1 | package com.appleyk.result; 2 | 3 | 4 | /** 5 | * 6 | * @blob http://blog.csdn.net/appleyk 7 | * @date 2018年5月10日-下午3:44:37 8 | * @param 9 | */ 10 | public enum ResponseMessage { 11 | 12 | /** 13 | * 成功 14 | */ 15 | OK(200,"成功"), 16 | 17 | /** 18 | * 错误的请求 19 | */ 20 | BAD_REQUEST(400,"错误的请求"), 21 | 22 | /** 23 | * 错误的请求 24 | */ 25 | NOTNULL_ID(400,"请求ID不能为空"), 26 | 27 | /** 28 | * 错误的请求 29 | */ 30 | NOTNULL_NAME(400,"名称不能为空"), 31 | 32 | 33 | /** 34 | * 内部错误 35 | */ 36 | INTERNAL_SERVER_ERROR(500, "内部错误"), 37 | 38 | 39 | /** 40 | * 操作太頻繁! 41 | */ 42 | FREQUENT_FEEDBACK(515, "操作太频繁,请五分钟后再提交!"); 43 | 44 | 45 | 46 | private final int status; 47 | 48 | private final String message; 49 | 50 | ResponseMessage(int status, String message){ 51 | this.status = status; 52 | this.message = message; 53 | } 54 | 55 | public int getStatus() { 56 | return status; 57 | } 58 | 59 | public String getMessage() { 60 | return message; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/appleyk/result/ResponseResult.java: -------------------------------------------------------------------------------- 1 | package com.appleyk.result; 2 | 3 | import java.io.Serializable; 4 | import java.util.ArrayList; 5 | import java.util.Date; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | import org.springframework.context.support.DefaultMessageSourceResolvable; 11 | import org.springframework.validation.BindingResult; 12 | 13 | import com.fasterxml.jackson.annotation.JsonFormat; 14 | import com.fasterxml.jackson.annotation.JsonInclude; 15 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 16 | 17 | /** 18 | * 19 | * @blob http://blog.csdn.net/appleyk 20 | * @date 2018年5月10日-下午3:44:37 21 | * @param 22 | */ 23 | public class ResponseResult implements Serializable { 24 | 25 | private static final long serialVersionUID = 2719931935414658118L; 26 | 27 | private final Integer status; 28 | 29 | private final String message; 30 | 31 | @JsonInclude(value = Include.NON_NULL) 32 | private final Object data; 33 | 34 | @JsonInclude(value = Include.NON_EMPTY) 35 | private final String[] exceptions; 36 | 37 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") 38 | private final Date timestamp; 39 | 40 | public ResponseResult(Integer status, String message) { 41 | 42 | super(); 43 | this.status = status; 44 | this.message = message; 45 | this.data = null; 46 | this.timestamp = new Date(); 47 | this.exceptions = null; 48 | 49 | } 50 | 51 | /** 52 | * 处理返回的resultData 53 | * @param result 54 | */ 55 | public ResponseResult(ResultData result) { 56 | 57 | super(); 58 | 59 | this.status = result.getState().getStatus(); 60 | this.message = result.getState().getMessage(); 61 | this.data = result.getData(); 62 | this.timestamp = new Date(); 63 | this.exceptions = null; 64 | } 65 | 66 | public ResponseResult(ResponseMessage rm){ 67 | super(); 68 | 69 | this.status = rm.getStatus(); 70 | this.message = rm.getMessage(); 71 | this.data = null; 72 | this.timestamp = new Date(); 73 | this.exceptions = null; 74 | } 75 | 76 | //UnauthorizedMessage 为自定义的消息---未认证 77 | // public ResponseResult(UnauthorizedMessage um){ 78 | // super(); 79 | // 80 | // this.status = um.getStatus(); 81 | // this.message = um.getMessage(); 82 | // this.data = null; 83 | // this.timestamp = new Date(); 84 | // this.exceptions = null; 85 | // } 86 | 87 | public ResponseResult(Integer status, String message, Object data) { 88 | 89 | super(); 90 | 91 | this.status = status; 92 | 93 | this.message = message; 94 | 95 | this.data = data; 96 | this.timestamp = new Date(); 97 | this.exceptions = null; 98 | 99 | } 100 | 101 | /** 102 | * 验证失败返回结果 103 | * @param responseMessage 104 | * @param result 105 | */ 106 | public ResponseResult(ResponseMessage responseMessage, BindingResult result) { 107 | 108 | super(); 109 | 110 | /** 111 | * 解析BindingResult,放入map 112 | */ 113 | List> errors = new ArrayList>(); 114 | 115 | for(int i=0;i map = new HashMap(); 117 | DefaultMessageSourceResolvable dm = (DefaultMessageSourceResolvable) result.getAllErrors().get(i).getArguments()[0]; 118 | map.put("field", dm.getDefaultMessage()); 119 | map.put("message", result.getAllErrors().get(i).getDefaultMessage()); 120 | errors.add(map); 121 | } 122 | 123 | this.status = responseMessage.getStatus(); 124 | 125 | this.message = responseMessage.getMessage(); 126 | 127 | this.data = errors; 128 | this.timestamp = new Date(); 129 | this.exceptions = null; 130 | 131 | } 132 | 133 | public ResponseResult(Integer status, String message, String key, Object value) { 134 | 135 | super(); 136 | 137 | this.status = status; 138 | 139 | this.message = message; 140 | 141 | Map map = new HashMap(); 142 | 143 | if (key == null || ("").equals(key)) { 144 | map.put("key", value); 145 | } else { 146 | map.put(key, value); 147 | } 148 | 149 | this.data = map; 150 | 151 | this.timestamp = new Date(); 152 | this.exceptions = null; 153 | 154 | } 155 | 156 | public ResponseResult(Integer status, Throwable ex) { 157 | 158 | super(); 159 | 160 | this.status = status; 161 | this.message = ex.getMessage(); 162 | this.data = null; 163 | StackTraceElement[] stackTeanceElement = ex.getStackTrace(); 164 | this.exceptions = new String[stackTeanceElement.length]; 165 | for (int i = 0; i < stackTeanceElement.length; i++) { 166 | this.exceptions[i] = stackTeanceElement[i].toString(); 167 | } 168 | this.timestamp = new Date(); 169 | } 170 | 171 | public ResponseResult(Integer status, String message, Throwable ex) { 172 | 173 | super(); 174 | 175 | this.status = status; 176 | 177 | this.message = message; 178 | 179 | this.data = null; 180 | 181 | StackTraceElement[] stackTeanceElement = ex.getStackTrace(); 182 | this.exceptions = new String[stackTeanceElement.length]; 183 | for (int i = 0; i < stackTeanceElement.length; i++) { 184 | this.exceptions[i] = stackTeanceElement[i].toString(); 185 | } 186 | 187 | this.timestamp = new Date(); 188 | 189 | } 190 | 191 | public Integer getStatus() { 192 | return status; 193 | } 194 | 195 | public String getMessage() { 196 | return message; 197 | } 198 | 199 | public Object getData() { 200 | return data; 201 | } 202 | 203 | public String[] getExceptions() { 204 | return exceptions; 205 | } 206 | 207 | public Date getTimestamp() { 208 | return timestamp; 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /src/main/java/com/appleyk/result/ResultData.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.appleyk.result; 5 | 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | 11 | /** 12 | * 13 | * @blob http://blog.csdn.net/appleyk 14 | * @date 2018年5月10日-下午3:44:37 15 | * @param 16 | */ 17 | public class ResultData { 18 | 19 | private ResponseMessage state; 20 | private Object data; 21 | private List dataList; 22 | 23 | 24 | public ResultData(ResponseMessage state) { 25 | 26 | this.state = state; 27 | } 28 | 29 | public ResultData(ResponseMessage state, Object data) { 30 | this.data = data; 31 | this.state = state; 32 | } 33 | 34 | public ResultData(ResponseMessage state, long data, boolean isId){ 35 | this.state = state; 36 | Map map = new HashMap(); 37 | map.put("id", data); 38 | this.data = map; 39 | } 40 | 41 | public ResultData(ResponseMessage state, long id){ 42 | this.state = state; 43 | Map map = new HashMap(); 44 | map.put("id", id); 45 | this.data = map; 46 | } 47 | 48 | /** 49 | * @return the data 50 | */ 51 | public Object getData() { 52 | return data; 53 | } 54 | 55 | public ResponseMessage getState(){ 56 | return state; 57 | } 58 | 59 | public List getDataList(){ 60 | return dataList; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/appleyk/service/QuestionService.java: -------------------------------------------------------------------------------- 1 | package com.appleyk.service; 2 | 3 | public interface QuestionService { 4 | 5 | void showDictPath(); 6 | String answer(String question) throws Exception; 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/appleyk/service/impl/QuestionServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.appleyk.service.impl; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileReader; 7 | import java.io.IOException; 8 | import java.math.BigDecimal; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.beans.factory.annotation.Value; 14 | import org.springframework.context.annotation.Primary; 15 | import org.springframework.stereotype.Service; 16 | 17 | import com.appleyk.process.ModelProcess; 18 | import com.appleyk.repository.QuestionRepository; 19 | import com.appleyk.service.QuestionService; 20 | import com.hankcs.hanlp.dictionary.CustomDictionary; 21 | 22 | @Service 23 | @Primary 24 | public class QuestionServiceImpl implements QuestionService { 25 | 26 | @Value("${rootDirPath}") 27 | private String rootDictPath; 28 | 29 | @Value("${HanLP.CustomDictionary.path.movieDict}") 30 | private String movieDictPath; 31 | 32 | @Value("${HanLP.CustomDictionary.path.genreDict}") 33 | private String genreDictPath; 34 | 35 | @Value("${HanLP.CustomDictionary.path.scoreDict}") 36 | private String scoreDictPath; 37 | 38 | @Autowired 39 | private QuestionRepository questionRepository; 40 | 41 | @Override 42 | public void showDictPath() { 43 | System.out.println("HanLP分词字典及自定义问题模板根目录:" + rootDictPath); 44 | System.out.println("用户自定义扩展词库【电影】:" + movieDictPath); 45 | } 46 | 47 | @Override 48 | public String answer(String question) throws Exception { 49 | 50 | ModelProcess queryProcess = new ModelProcess(rootDictPath); 51 | 52 | /** 53 | * 加载自定义的电影字典 == 设置词性 nm 0 54 | */ 55 | 56 | loadMovieDict(movieDictPath); 57 | 58 | /** 59 | * 加载自定义的类型字典 == 设置词性 ng 0 60 | */ 61 | loadGenreDict(genreDictPath); 62 | 63 | /** 64 | * 加载自定义的评分字典 == 设置词性 x 0 65 | */ 66 | loadScoreDict(scoreDictPath); 67 | ArrayList reStrings = queryProcess.analyQuery(question); 68 | int modelIndex = Integer.valueOf(reStrings.get(0)); 69 | String answer = null; 70 | String title = ""; 71 | String name = ""; 72 | String type = ""; 73 | Double score = 0.0; 74 | /** 75 | * 匹配问题模板 76 | */ 77 | switch (modelIndex) { 78 | case 0: 79 | /** 80 | * nm 评分 == 电影评分 81 | */ 82 | title = reStrings.get(1); 83 | score = questionRepository.getMovieRating(title); 84 | if (score != null) { 85 | BigDecimal b = new BigDecimal(score); 86 | // 四舍五入取两位小数 87 | answer = String.valueOf(b.setScale(2, BigDecimal.ROUND_HALF_UP).floatValue()); 88 | } else { 89 | answer = null; 90 | } 91 | break; 92 | case 1: 93 | /** 94 | * nm 上映时间 == 电影上映时间 95 | */ 96 | title = reStrings.get(1); 97 | String releaseDate = questionRepository.getMovieReleaseDate(title); 98 | if (releaseDate != null) { 99 | answer = releaseDate; 100 | } else { 101 | answer = null; 102 | } 103 | break; 104 | case 2: 105 | /** 106 | * nm 类型 == 电影类型 107 | */ 108 | title = reStrings.get(1); 109 | List types = questionRepository.getMovieTypes(title); 110 | if (types.size() == 0) { 111 | answer = null; 112 | } else { 113 | answer = types.toString().replace("[", "").replace("]", ""); 114 | } 115 | break; 116 | case 3: 117 | /** 118 | * nm 简介 == 电影简介、详情 119 | */ 120 | title = reStrings.get(1); 121 | answer = questionRepository.getMovieInfo(title); 122 | break; 123 | case 4: 124 | /** 125 | * nm 演员列表 == 电影演员列表 126 | */ 127 | title = reStrings.get(1); 128 | List actors = questionRepository.getMovieActors(title); 129 | if (actors.size() == 0) { 130 | answer = null; 131 | } else { 132 | answer = actors.toString().replace("[", "").replace("]", ""); 133 | } 134 | break; 135 | case 5: 136 | /** 137 | * nnt 介绍 == 演员简介 138 | */ 139 | name = reStrings.get(1); 140 | answer = questionRepository.getActorInfo(name); 141 | break; 142 | case 6: 143 | /** 144 | * nnt 电影类型 ng == 演员演过的x类型的电影有哪些 145 | */ 146 | name = reStrings.get(1); 147 | type = reStrings.get(2); 148 | if (type.indexOf("片") > 0) { 149 | type = type.substring(0, type.indexOf("片")); 150 | } 151 | // 模糊查询拼接参数 == 包含type的电影都查出来 152 | type = ".*" + type + "*."; 153 | List movies = questionRepository.getActorMoviesByType(name, type); 154 | if (movies.size() == 0) { 155 | answer = null; 156 | } else { 157 | answer = movies.toString().replace("[", "").replace("]", ""); 158 | } 159 | break; 160 | case 7: 161 | /** 162 | * nnt 电影作品 == 演员的电影作品有哪些 163 | */ 164 | name = reStrings.get(1); 165 | List actorMovies = questionRepository.getActorMovies(name); 166 | if (actorMovies.size() == 0) { 167 | answer = null; 168 | } else { 169 | answer = actorMovies.toString().replace("[", "").replace("]", ""); 170 | } 171 | break; 172 | case 8: 173 | /** 174 | * 1 2 3 4 nnt 参演评分 大于 x == 演员参演的电影评分大于x的有哪些 175 | */ 176 | name = reStrings.get(1); 177 | score = Double.parseDouble(reStrings.get(4)); 178 | List actorMoviesByScore = questionRepository.getActorMoviesByHScore(name, score); 179 | if (actorMoviesByScore.size() == 0) { 180 | answer = null; 181 | } else { 182 | answer = actorMoviesByScore.toString().replace("[", "").replace("]", ""); 183 | } 184 | break; 185 | case 9: 186 | /** 187 | * 1 2 3 4 nnt 参演评分 小于 x == 演员参演的电影评分小于x的有哪些 188 | */ 189 | name = reStrings.get(1); 190 | score = Double.parseDouble(reStrings.get(4)); 191 | List actorMoviesByLScore = questionRepository.getActorMoviesByLScore(name, score); 192 | if (actorMoviesByLScore.size() == 0) { 193 | answer = null; 194 | } else { 195 | answer = actorMoviesByLScore.toString().replace("[", "").replace("]", ""); 196 | } 197 | 198 | break; 199 | case 10: 200 | /** 201 | * nnt 电影类型 == 演员参演的电影类型有哪些 202 | */ 203 | name = reStrings.get(1); 204 | List movieTypes = questionRepository.getActorMoviesType(name); 205 | if (movieTypes.size() == 0) { 206 | answer = null; 207 | } else { 208 | answer = movieTypes.toString().replace("[", "").replace("]", ""); 209 | } 210 | break; 211 | case 11: 212 | /** 213 | * 1 2 3 4 nnt nnr 合作 电影列表 == 演员A和演员B合作的电影有哪些 214 | */ 215 | name = reStrings.get(1); 216 | List actorMoviesA = questionRepository.getActorMovies(name); 217 | /** 218 | * 如果演员A的电影作品无,那么A和演员B无合作之谈 219 | */ 220 | if (actorMoviesA.size() == 0) { 221 | answer = null; 222 | break; 223 | } 224 | 225 | name = reStrings.get(2); 226 | List actorMoviesB = questionRepository.getActorMovies(name); 227 | /** 228 | * 如果演员B的电影作品无,那么B和演员A无合作之谈 229 | */ 230 | if (actorMoviesB.size() == 0) { 231 | answer = null; 232 | break; 233 | } 234 | 235 | /** 236 | * A的作品与B的作品求交集 237 | */ 238 | actorMoviesA.retainAll(actorMoviesB); 239 | 240 | if (actorMoviesA.size() == 0) { 241 | answer = null; 242 | } else { 243 | answer = actorMoviesA.toString().replace("[", "").replace("]", ""); 244 | } 245 | break; 246 | case 12: 247 | name = reStrings.get(1); 248 | Integer count = questionRepository.getMoviesCount(name); 249 | if (count == null) { 250 | answer = null; 251 | } else { 252 | answer = String.valueOf(count) + "部电影"; 253 | } 254 | break; 255 | case 13: 256 | /** 257 | * nnt 出生日期 == 演员出生日期 258 | */ 259 | name = reStrings.get(1); 260 | answer = questionRepository.getActorBirth(name); 261 | break; 262 | default: 263 | break; 264 | } 265 | 266 | System.out.println(answer); 267 | if (answer != null && !answer.equals("") && !answer.equals("\\N")) { 268 | return answer; 269 | } else { 270 | return "sorry,我没有找到你要的答案"; 271 | } 272 | } 273 | 274 | /** 275 | * 加载自定义电影字典 276 | * 277 | * @param path 278 | */ 279 | public void loadMovieDict(String path) { 280 | 281 | File file = new File(path); 282 | BufferedReader br = null; 283 | try { 284 | br = new BufferedReader(new FileReader(file)); 285 | addCustomDictionary(br, 0); 286 | } catch (FileNotFoundException e1) { 287 | e1.printStackTrace(); 288 | } 289 | 290 | } 291 | 292 | /** 293 | * 加载自定义电影类别字典 294 | * 295 | * @param path 296 | */ 297 | public void loadGenreDict(String path) { 298 | 299 | File file = new File(path); 300 | BufferedReader br = null; 301 | try { 302 | br = new BufferedReader(new FileReader(file)); 303 | addCustomDictionary(br, 1); 304 | } catch (FileNotFoundException e1) { 305 | e1.printStackTrace(); 306 | } 307 | } 308 | 309 | /** 310 | * 加载自定义电影评分字典 311 | * 312 | * @param path 313 | */ 314 | public void loadScoreDict(String path) { 315 | 316 | File file = new File(path); 317 | BufferedReader br = null; 318 | try { 319 | br = new BufferedReader(new FileReader(file)); 320 | addCustomDictionary(br, 2); 321 | } catch (FileNotFoundException e1) { 322 | e1.printStackTrace(); 323 | } 324 | } 325 | 326 | /** 327 | * 添加自定义分词及其词性,注意数字0表示频率,不能没有 328 | * 329 | * @param br 330 | * @param type 331 | */ 332 | public void addCustomDictionary(BufferedReader br, int type) { 333 | 334 | String word; 335 | try { 336 | while ((word = br.readLine()) != null) { 337 | switch (type) { 338 | /** 339 | * 设置电影名词词性 == nm 0 340 | */ 341 | case 0: 342 | CustomDictionary.add(word, "nm 0"); 343 | break; 344 | /** 345 | * 设置电影类型名词 词性 == ng 0 346 | */ 347 | case 1: 348 | CustomDictionary.add(word, "ng 0"); 349 | break; 350 | /** 351 | * 设置电影评分数词 词性 == x 0 352 | */ 353 | case 2: 354 | CustomDictionary.add(word, "x 0"); 355 | break; 356 | default: 357 | break; 358 | } 359 | } 360 | br.close(); 361 | } catch (NumberFormatException e) { 362 | e.printStackTrace(); 363 | } catch (IOException e) { 364 | e.printStackTrace(); 365 | } 366 | } 367 | } 368 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8080 2 | server.servlet.session.timeout=10 3 | server.tomcat.uri-encoding=utf8 4 | 5 | #在application.properties文件中引入日志配置文件 6 | #===================================== log ============================= 7 | logging.config=classpath:logback-boot.xml 8 | 9 | #Neo4j配置 10 | spring.data.neo4j.username=neo4j 11 | spring.data.neo4j.password=admin 12 | #数据库uri地址 13 | spring.data.neo4j.uri=bolt://localhost:7687 14 | 15 | #HanLP分词字典及自定义问题模板根目录 16 | rootDirPath=D:/HanLP/data 17 | 18 | #HanLP 用户自定义扩展词库,不建议使用HanLP自定义词典追加的模式,建议自行加载 19 | HanLP.CustomDictionary.path.movieDict=${rootDirPath}/dictionary/custom/movieDict.txt 20 | HanLP.CustomDictionary.path.genreDict=${rootDirPath}/dictionary/custom/genreDict.txt 21 | HanLP.CustomDictionary.path.scoreDict=${rootDirPath}/dictionary/custom/scoreDict.txt 22 | -------------------------------------------------------------------------------- /src/main/resources/hanlp.properties: -------------------------------------------------------------------------------- 1 | #本配置文件中的路径的根目录,根目录+其他路径=完整路径(支持相对路径,请参考:https://github.com/hankcs/HanLP/pull/254) 2 | #Windows用户请注意,路径分隔符统一使用/ 3 | root=D:/HanLP/ 4 | #核心词典路径 5 | CoreDictionaryPath=data/dictionary/CoreNatureDictionary.txt 6 | #2元语法词典路径 7 | BiGramDictionaryPath=data/dictionary/CoreNatureDictionary.ngram.txt 8 | #停用词词典路径 9 | CoreStopWordDictionaryPath=data/dictionary/stopwords.txt 10 | #同义词词典路径 11 | CoreSynonymDictionaryDictionaryPath=data/dictionary/synonym/CoreSynonym.txt 12 | #人名词典路径 13 | PersonDictionaryPath=data/dictionary/person/nr.txt 14 | #人名词典转移矩阵路径 15 | PersonDictionaryTrPath=data/dictionary/person/nr.tr.txt 16 | #繁简词典根目录 17 | tcDictionaryRoot=data/dictionary/tc 18 | #自定义词典路径,用;隔开多个自定义词典,空格开头表示在同一个目录,使用“文件名 词性”形式则表示这个词典的词性默认是该词性。优先级递减。 19 | #另外data/dictionary/custom/CustomDictionary.txt是个高质量的词库,请不要删除。所有词典统一使用【UTF-8】编码。 20 | #注意,每次更新自己定义的新词典myDict.txt的内容时,要删除同目录下的词典缓存文件CustomDictionary.txt.bin 21 | 22 | # 现代汉语补充词库.txt; 这个词典中的卧虎藏龙与自定义的电影词典中的卧虎藏龙有冲突 23 | CustomDictionaryPath=data/dictionary/custom/CustomDictionary.txt; 全国地名大全.txt ns; 人名词典.txt; 机构名词典.txt; 上海地名.txt ns;data/dictionary/person/nrf.txt nrf; 24 | 25 | #CRF分词模型路径 26 | CRFSegmentModelPath=data/model/segment/CRFSegmentModel.txt 27 | #HMM分词模型 28 | HMMSegmentModelPath=data/model/segment/HMMSegmentModel.bin 29 | #分词结果是否展示词性 30 | ShowTermNature=true 31 | #IO适配器,实现com.hankcs.hanlp.corpus.io.IIOAdapter接口以在不同的平台(Hadoop、Redis等)上运行HanLP 32 | #默认的IO适配器如下,该适配器是基于普通文件系统的。 33 | #IOAdapter=com.hankcs.hanlp.corpus.io.FileIOAdapter 34 | #感知机词法分析器 35 | PerceptronCWSModelPath=data/model/perceptron/pku199801/cws.bin 36 | PerceptronPOSModelPath=data/model/perceptron/pku199801/pos.bin 37 | PerceptronNERModelPath=data/model/perceptron/pku199801/ner.bin 38 | #CRF词法分析器 39 | CRFCWSModelPath=data/model/crf/pku199801/cws.bin 40 | CRFPOSModelPath=data/model/crf/pku199801/pos.bin 41 | CRFNERModelPath=data/model/crf/pku199801/ner.bin 42 | #更多配置项请参考 https://github.com/hankcs/HanLP/blob/master/src/main/java/com/hankcs/hanlp/HanLP.java#L59 自行添加 -------------------------------------------------------------------------------- /src/main/resources/logback-boot.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %d %p (%file:%line\)- %m%n 8 | 9 | UTF-8 10 | 11 | 12 | 13 | 14 | 15 | 17 | 18 | opt/spring-boot-web/logs/sys.log 19 | 20 | 21 | 22 | 23 | 24 | log/sys.%d.%i.log 25 | 26 | 30 27 | 28 | 29 | 10MB 30 | 31 | 32 | 33 | 34 | 35 | %d %p (%file:%line\)- %m%n 36 | 37 | 38 | UTF-8 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 基于电影知识图谱的智能问答系统 -- Appleyk专栏 8 | 69 | 96 | 195 | 196 | 197 | 198 | 199 |
200 |
    201 |
  • 你好,我是机器人小鱼,你有什么电影方面的问题可以问我哦
  • 202 |
    203 |
204 | 205 | 206 |
207 | 208 | 209 | 357 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Spring-Neo4j-Movie 4 | 5 | index.html 6 | index.htm 7 | index.jsp 8 | default.html 9 | default.htm 10 | default.jsp 11 | 12 | -------------------------------------------------------------------------------- /src/test/java/BayesTest.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.List; 3 | 4 | import org.apache.spark.SparkConf; 5 | import org.apache.spark.api.java.JavaRDD; 6 | import org.apache.spark.api.java.JavaSparkContext; 7 | import org.apache.spark.mllib.classification.NaiveBayes; 8 | import org.apache.spark.mllib.classification.NaiveBayesModel; 9 | import org.apache.spark.mllib.linalg.Vector; 10 | import org.apache.spark.mllib.linalg.Vectors; 11 | import org.apache.spark.mllib.regression.LabeledPoint; 12 | import org.junit.Test; 13 | 14 | public class BayesTest { 15 | 16 | @Test 17 | public void TestA(){ 18 | 19 | /** 20 | * 本地模式,*表示启用多个线程并行计算 21 | */ 22 | SparkConf conf = new SparkConf().setAppName("NaiveBayesTest").setMaster("local[*]"); 23 | JavaSparkContext sc = new JavaSparkContext(conf); 24 | 25 | 26 | /** 27 | * MLlib的本地向量主要分为两种,DenseVector和SparseVector 28 | * 前者是用来保存稠密向量,后者是用来保存稀疏向量 29 | */ 30 | 31 | /** 32 | * 短发(1) 长发(2) 运动鞋(3) 高跟鞋(4) 喉结(5) 皮肤白(6) 33 | */ 34 | 35 | /** 36 | * 两种方式分别创建向量 == 其实创建稀疏向量的方式有两种,本文只讲一种 37 | * (1.0, 0.0, 1.0, 0.0, 1.0, 0.0) 38 | * (1.0, 1.0, 1.0, 1.0, 0.0, 1.0) 39 | */ 40 | 41 | //稠密向量 == 连续的 42 | Vector vMale = Vectors.dense(1,0,1,0,1,0); 43 | 44 | 45 | //稀疏向量 == 间隔的、指定的,未指定位置的向量值默认 = 0.0 46 | int len = 6; 47 | int[] index = new int[]{0,1,2,3,5}; 48 | double[] values = new double[]{1,1,1,1,1}; 49 | //索引0、1、2、3、5位置上的向量值=1,索引4没给出,默认0 50 | Vector vFemale = Vectors.sparse(len, index, values); 51 | //System.err.println("vFemale == "+vFemale); 52 | /** 53 | * labeled point 是一个局部向量,要么是密集型的要么是稀疏型的 54 | * 用一个label/response进行关联 55 | * 在MLlib里,labeled points 被用来监督学习算法 56 | * 我们使用一个double数来存储一个label,因此我们能够使用labeled points进行回归和分类 57 | * 在二进制分类里,一个label可以是 0(负数)或者 1(正数) 58 | * 在多级分类中,labels可以是class的索引,从0开始:0,1,2,...... 59 | */ 60 | 61 | //训练集生成 ,规定数据结构为LabeledPoint == 构建方式:稠密向量模式 ,1.0:类别编号 == 男性 62 | LabeledPoint train_one = new LabeledPoint(1.0,vMale); //(1.0, 0.0, 1.0, 0.0, 1.0, 0.0) 63 | //训练集生成 ,规定数据结构为LabeledPoint == 构建方式:稀疏向量模式 ,2.0:类别编号 == 女性 64 | LabeledPoint train_two = new LabeledPoint(2.0,vFemale); //(1.0, 1.0, 1.0, 1.0, 0.0, 1.0) 65 | //我们也可以给同一个类别增加多个训练集 66 | LabeledPoint train_three = new LabeledPoint(2.0,Vectors.dense(0,1,1,1,0,1)); 67 | 68 | //List存放训练集【三个训练样本数据】 69 | List trains = new ArrayList<>(); 70 | trains.add(train_one); 71 | trains.add(train_two); 72 | trains.add(train_three); 73 | 74 | /** 75 | * SPARK的核心是RDD(弹性分布式数据集) 76 | * Spark是Scala写的,JavaRDD就是Spark为Java写的一套API 77 | * JavaSparkContext sc = new JavaSparkContext(sparkConf); //对应JavaRDD 78 | * SparkContext sc = new SparkContext(sparkConf) ; //对应RDD 79 | * 数据类型为LabeledPoint 80 | */ 81 | JavaRDD trainingRDD = sc.parallelize(trains); 82 | 83 | /** 84 | * 利用Spark进行数据分析时,数据一般要转化为RDD 85 | * JavaRDD转Spark的RDD 86 | */ 87 | NaiveBayesModel nb_model = NaiveBayes.train(trainingRDD.rdd()); 88 | 89 | //测试集生成 == 以下的向量表示,这个人具有特征:短发(1),运动鞋(3) 90 | // double [] dTest = {0,0,0,0,1,0}; 91 | double [] dTest = {0,1,1,1,0,1}; 92 | Vector vTest = Vectors.dense(dTest);//测试对象为单个vector,或者是RDD化后的vector 93 | 94 | //朴素贝叶斯用法 95 | int modelIndex =(int) nb_model.predict(vTest); 96 | System.out.println("标签分类编号:"+modelIndex);// 分类结果 == 返回分类的标签值 97 | /** 98 | * 计算测试目标向量与训练样本数据集里面对应的各个分类标签匹配的概率结果 99 | */ 100 | System.out.println(nb_model.predictProbabilities(vTest)); 101 | if(modelIndex == 1){ 102 | System.out.println("答案:贝叶斯分类器推断这个人的性别是男性"); 103 | }else if(modelIndex == 2){ 104 | System.out.println("答案:贝叶斯分类器推断这个人的性别是女性"); 105 | } 106 | //最后不要忘了释放资源 107 | sc.close(); 108 | 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/test/java/HanLPTest.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.List; 3 | 4 | import org.apache.spark.SparkConf; 5 | import org.apache.spark.api.java.JavaRDD; 6 | import org.apache.spark.api.java.JavaSparkContext; 7 | import org.apache.spark.mllib.classification.NaiveBayes; 8 | import org.apache.spark.mllib.classification.NaiveBayesModel; 9 | import org.apache.spark.mllib.linalg.Vector; 10 | import org.apache.spark.mllib.linalg.Vectors; 11 | import org.apache.spark.mllib.regression.LabeledPoint; 12 | import org.junit.Test; 13 | 14 | import com.appleyk.process.ModelProcess; 15 | import com.hankcs.hanlp.HanLP; 16 | import com.hankcs.hanlp.dictionary.CustomDictionary; 17 | import com.hankcs.hanlp.seg.Segment; 18 | import com.hankcs.hanlp.seg.common.Term; 19 | 20 | public class HanLPTest { 21 | 22 | @Test 23 | public void TestA(){ 24 | String lineStr = "明天虽然会下雨,但是我还是会看周杰伦的演唱会。"; 25 | try{ 26 | Segment segment = HanLP.newSegment(); 27 | segment.enableCustomDictionary(true); 28 | /** 29 | * 自定义分词+词性 30 | */ 31 | CustomDictionary.add("虽然会","ng 0"); 32 | List seg = segment.seg(lineStr); 33 | for (Term term : seg) { 34 | System.out.println(term.toString()); 35 | } 36 | }catch(Exception ex){ 37 | System.out.println(ex.getClass()+","+ex.getMessage()); 38 | } 39 | } 40 | @Test 41 | public void TestB(){ 42 | HanLP.Config.Normalization = true; 43 | CustomDictionary.insert("爱听4G", "nz 1000"); 44 | System.out.println(HanLP.segment("爱听4g")); 45 | System.out.println(HanLP.segment("爱听4G")); 46 | System.out.println(HanLP.segment("爱听4G")); 47 | System.out.println(HanLP.segment("爱听4G")); 48 | System.out.println(HanLP.segment("愛聽4G")); 49 | } 50 | 51 | @Test 52 | public void TestC() throws Exception{ 53 | ModelProcess query = new ModelProcess("D:/HanLP/data"); 54 | String[] questionArr = new String[] {"卧虎藏龙的电影分数是多少"}; 55 | for(String que: questionArr){ 56 | ArrayList question = query.analyQuery(que); 57 | System.err.println(question); 58 | } 59 | } 60 | 61 | @Test 62 | public void TestRDD(){ 63 | 64 | SparkConf conf = new SparkConf().setAppName("NaiveBayesTest").setMaster("local[*]"); 65 | JavaSparkContext sc = new JavaSparkContext(conf); 66 | 67 | 68 | /** 69 | * MLlib的本地向量主要分为两种,DenseVector和SparseVector 70 | * 前者是用来保存稠密向量,后者是用来保存稀疏向量 71 | */ 72 | 73 | /** 74 | * 两种方式分别创建向量 == 其实创建稀疏向量的方式有两种,本文只讲一种 75 | * (1.0, 0.0, 2.0) 76 | * (2.0, 3.0, 0.0) 77 | */ 78 | 79 | //稠密向量 == 连续的 80 | Vector dense = Vectors.dense(1.0,0.0,2.0); 81 | System.out.println(dense); 82 | 83 | 84 | //稀疏向量 == 间隔的、指定的,未指定位置的向量值默认 = 0.0 85 | int len = 3; 86 | int[] index = new int[]{0,1}; 87 | double[] values = new double[]{2.0,3.0}; 88 | Vector sparse = Vectors.sparse(len, index, values); 89 | 90 | /** 91 | * labeled point 是一个局部向量,要么是密集型的要么是稀疏型的 92 | * 用一个label/response进行关联 93 | * 在MLlib里,labeled points 被用来监督学习算法 94 | * 我们使用一个double数来存储一个label,因此我们能够使用labeled points进行回归和分类 95 | * 在二进制分类里,一个label可以是 0(负数)或者 1(正数) 96 | * 在多级分类中,labels可以是class的索引,从0开始:0,1,2,...... 97 | */ 98 | 99 | //训练集生成 ,规定数据结构为LabeledPoint == 构建方式:稠密向量模式 ,1.0:类别编号 100 | LabeledPoint train_one = new LabeledPoint(1.0,dense); //(1.0, 0.0, 2.0) 101 | //训练集生成 ,规定数据结构为LabeledPoint == 构建方式:稀疏向量模式 ,2.0:类别编号 102 | LabeledPoint train_two = new LabeledPoint(2.0,sparse); //(2.0, 3.0, 0.0) 103 | //训练集生成 ,规定数据结构为LabeledPoint == 构建方式:稠密向量模式 ,3.0:类别编号 104 | LabeledPoint train_three = new LabeledPoint(3.0,Vectors.dense(1,1,2)); //(1.0, 1.0, 2.0) 105 | 106 | //List存放训练集【三个训练样本数据】 107 | List trains = new ArrayList<>(); 108 | trains.add(train_one); 109 | trains.add(train_two); 110 | trains.add(train_three); 111 | 112 | //获得弹性分布式数据集JavaRDD,数据类型为LabeledPoint 113 | JavaRDD trainingRDD = sc.parallelize(trains); 114 | 115 | /** 116 | * 利用Spark进行数据分析时,数据一般要转化为RDD 117 | * JavaRDD转Spark的RDD 118 | */ 119 | NaiveBayesModel nb_model = NaiveBayes.train(trainingRDD.rdd()); 120 | 121 | //测试集生成 122 | double [] dTest = {2,1,0}; 123 | Vector vTest = Vectors.dense(dTest);//测试对象为单个vector,或者是RDD化后的vector 124 | 125 | //朴素贝叶斯用法 126 | System.err.println(nb_model.predict(vTest));// 分类结果 == 返回分类的标签值 127 | /** 128 | * 计算测试目标向量与训练样本数据集里面对应的各个分类标签匹配的概率结果 129 | */ 130 | System.err.println(nb_model.predictProbabilities(vTest)); 131 | 132 | //最后不要忘了释放资源 133 | sc.close(); 134 | } 135 | 136 | } 137 | --------------------------------------------------------------------------------