├── .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