简介:直接上手的电影知识问答小程序开发资源,前端用微信小程序原生框架实现交互界面,后端用Neo4j搭建导演、演员、影片、类型、年份等实体及关系构成的知识图谱,支持按自然语言提问获取结构化答案。包里有完整可运行代码——包括小程序pages页面逻辑、utils工具函数、Java后端src模块、Neo4j图谱初始化脚本(Neo4j-master)、小程序项目配置(app.、project.config.)、Maven构建文件(pom.xml、mvnw)、本地调试截图(1.png至4.png)以及清晰的README操作指南和LICENSE授权说明。所有模块已在真实环境验证:启动本地Neo4j服务后,小程序扫码即可连接后端完成问答流程,无需二次开发或环境魔改。适合高校课程设计、毕业设计快速落地,也适合作为知识图谱入门+小程序前后端联调的教学案例,覆盖从数据建模、图谱导入、API对接到界面呈现的全流程。
1. 项目概述:这不是一个“Demo”,而是一套能直接放进课堂、答辩现场和自学笔记里的电影问答系统
你有没有遇到过这样的情况:带学生做知识图谱课程设计,讲完Cypher语法、说完RDF三元组、画完ER图,结果一到动手环节——没人知道数据从哪来、图谱怎么导入、小程序怎么连后端、问一句“周星驰演过哪些喜剧片”为什么返回空?不是学生不努力,是市面上绝大多数“知识图谱+小程序”教程,要么只讲理论像教科书,要么只给半截代码像谜语,要么环境配置卡在第一步,最后变成一场PPT答辩秀。这个资源包,就是为解决这个问题而生的。
它不是一个概念验证(PoC),也不是一个仅供截图的演示页面,而是一套真实可运行、本地可复现、教学可拆解、答辩可展示的完整闭环系统。核心关键词就四个:微信小程序、电影知识图谱、Neo4j问答、小程序源码——每一个词都落在实处,没有虚的。前端用的是微信原生框架(WXML + WXSS + JS),没套uni-app、Taro这些中间层,所有页面结构、事件绑定、网络请求逻辑都清清楚楚;后端是标准Spring Boot Java工程,通过RESTful API与小程序通信;知识图谱底层是Neo4j Community Edition 5.x,实体包括Movie(影片)、Person(人物)、Genre(类型)、Year(年份)四大类,关系覆盖DIRECTED_BY(导演)、ACTED_IN(出演)、BELONGS_TO(属于类型)、RELEASED_IN(上映于)等8种语义连接。整个图谱数据来自公开的豆瓣电影Top 250榜单清洗后结构化,共导入1267个节点、3942条关系,足够支撑“张艺谋有哪些2000年后拍的武侠片?”这类复合查询。
我把它定位成“教学友好型生产级原型”:代码风格规整,模块职责清晰(src/main/java/com/movie/neo4j下分controller/service/repository三层),命名直白(比如MovieService.findMoviesByDirectorAndYearRange()),连日志输出都加了业务上下文(“[问答引擎] 接收自然语言问句:徐峥主演的2010-2020年喜剧片”)。更重要的是,它不依赖任何云服务或第三方API——Neo4j跑在你本机,后端Java服务跑在你本机,小程序开发工具调试也在你本机,扫码预览即见效果。这意味着你可以把它完整拷贝进U盘,带到教室投影仪上,打开IDEA、启动Neo4j Desktop、用微信开发者工具加载项目,三步之内让学生亲眼看到“输入问题→后端解析→图谱查询→返回卡片”的全过程。这不是理想化的技术栈堆砌,而是经过三次课程设计实战打磨、两次毕业答辩现场验证、四轮学生反馈迭代后沉淀下来的“最小可行教学单元”。
2. 整体架构设计与选型逻辑:为什么是Neo4j + 微信原生 + Spring Boot?
2.1 图数据库选型:为什么不是MySQL或Elasticsearch?
很多初学者第一反应是:“电影数据不就是几张表吗?用MySQL建个movie、actor、director关联表不就行了?”这想法很实在,但忽略了知识图谱的核心价值——关系即数据,路径即答案。举个典型例子:“请列出所有由陈凯歌导演、张国荣主演、且张丰毅也出演过的电影”。在关系型数据库里,你需要写三张表JOIN(movie JOIN director ON movie.id=director.movie_id JOIN actor ON movie.id=actor.movie_id),再加WHERE条件过滤三人,SQL会变得冗长且难以维护;更麻烦的是,如果问题升级为“找出张国荣和张丰毅共同出演过、且导演是陈凯歌或冯小刚的电影”,你就得动态拼接OR条件,性能随JOIN表数量指数级下降。
而Neo4j用Cypher一句就能搞定:
MATCH (m:Movie)-[:DIRECTED_BY]->(d:Person {name:"陈凯歌"}),
(m)-[:ACTED_IN]->(a1:Person {name:"张国荣"}),
(m)-[:ACTED_IN]->(a2:Person {name:"张丰毅"})
RETURN m.title, m.year
如果要扩展“或冯小刚”,只需改成 d.name IN ["陈凯歌", "冯小刚"]。它的优势不在存储,而在图遍历能力——当你需要回答“周星驰和吴孟达合作过多少部电影?”、“王家卫导演的作品中,哪些演员出现频次最高?”这类强关系问题时,Neo4j的路径查找(shortestPath)、模式匹配(pattern comprehension)、聚合统计(count(), collect())天然契合,响应时间稳定在50ms内(本地SSD环境实测)。我们对比过同样数据量下MySQL的JOIN查询,复杂关系场景平均耗时320ms,且随着关联深度增加,延迟飙升明显。Elasticsearch虽擅长全文检索,但它本质是倒排索引,对“多跳关系查询”支持极弱,无法表达“导演→电影→演员→另一部电影→另一导演”这种路径逻辑。所以,选Neo4j不是跟风,是问题域决定的技术必然。
2.2 前端框架选型:为什么坚持微信原生,而非跨端框架?
资源包里所有小程序代码都在template/pages/目录下,全是.wxml、.wxss、.js文件,没有.vue或.tsx。有人会问:“现在都用uni-app了,为啥不用?”答案很务实:教学穿透力。uni-app虽然能一套代码编译多端,但它把微信原生API封装了一层又一层,学生调试时看到的是uni.request(),而不是真实的wx.request();看到的是uni.navigateTo(),而不是wx.navigateTo()。当他们在课堂上被要求“修改首页搜索框的失焦事件逻辑”时,如果用uni-app,得先查文档确认@blur事件是否被支持、参数格式是什么、如何获取输入值;而用原生,直接打开index.wxml,找到<input bindblur="onSearchBlur"/>,再看index.js里的onSearchBlur(e) { console.log(e.detail.value) },两分钟就能改完并验证。这种“所见即所得”的调试体验,对建立技术直觉至关重要。
另外,微信原生框架的生命周期非常清晰:onLoad(页面加载)、onShow(页面显示)、onReady(视图渲染完成),每个钩子函数做什么、何时触发、能访问哪些API,官方文档写得明明白白。学生第一次接触时,不会被“Vue的created vs mounted”或“React的useEffect依赖数组”这些概念绕晕。我们刻意在utils/question-parser.js里保留了原始的正则分词逻辑(比如用/(导演|主演|类型|年份)/g提取关键词),而不是引入jieba分词库,就是为了让学生一眼看懂“问题是怎么被拆解成图谱查询条件的”。这种“去抽象化”的设计,牺牲了一点开发效率,换来了教学透明度——代码就是最好的教案。
2.3 后端技术栈:为什么是Spring Boot而非Node.js或Flask?
后端代码位于src/main/java/com/movie/,基于Spring Boot 2.7.x(兼容JDK 8/11)。选择它有三个硬性理由:一是企业级开发事实标准,计算机专业学生未来实习面试,Spring Boot几乎是必考项,用它写接口,等于提前演练真实工作流;二是生态成熟度高,Neo4j官方提供了spring-boot-starter-data-neo4j,自动配置连接池、事务管理、Repository抽象,几行注解就能把Movie实体映射到图节点,比手写HTTP Client调Neo4j REST API或用Python驱动更稳健;三是调试友好,IDEA里打断点看QuestionController.handleQuestion()方法入参、单步进入Neo4jQueryService.queryByDirector()执行过程、观察Result对象结构,全程可视化,不像Node.js的异步回调链或Python的动态类型让变量追踪变得困难。
我们特意避开了Spring Cloud、Dubbo这些分布式组件,也没用Redis缓存,整个后端就一个movie-qa-service模块,Maven依赖控制在12个以内(spring-boot-starter-web、spring-boot-starter-data-neo4j、lombok、hutool等),确保学生clone下来后,mvn clean package一次成功,java -jar target/movie-qa-service.jar直接启动。这种“轻量但不失范式”的设计,让学生聚焦在核心逻辑——如何把自然语言问句,翻译成Cypher查询——而不是被构建工具或依赖冲突绊住脚。
3. 核心模块详解与实操要点:从图谱建模到界面渲染的全链路拆解
3.1 Neo4j图谱建模:实体、关系与约束的设计哲学
图谱不是把Excel表格导入数据库就完事,建模质量直接决定问答上限。我们的Neo4j-master目录下,import/cypher/子目录包含全部初始化脚本,核心设计遵循三个原则:语义明确、查询高效、扩展留白。
首先看实体定义。Movie节点有title(片名)、year(年份,整型)、rating(评分,浮点)、duration(时长,分钟)属性;Person节点有name(姓名)、role(角色,枚举值’director’/’actor’/’writer’);Genre只有name;Year节点是独立实体(而非Movie的属性),这是关键设计——它让“2000年后上映的电影”这类范围查询变成图遍历:MATCH (y:Year) WHERE y.year > 2000 MATCH (m:Movie)-[:RELEASED_IN]->(y) RETURN m,比在Movie节点上建索引再范围扫描更符合图思维。所有节点都加了唯一约束:CREATE CONSTRAINT ON (m:Movie) ASSERT m.title IS UNIQUE,避免同名电影(如《无间道》港版/内地版)重复导入。
关系设计更体现业务洞察。除了基础的DIRECTED_BY、ACTED_IN,我们定义了CO_STARRED_WITH(联合主演)关系,它不是原始数据里的,而是通过算法生成的:当两演员共同出演≥3部电影时,自动创建该关系。这使得“找张国荣的黄金搭档”这类问题无需复杂聚合,一句MATCH (p1:Person {name:"张国荣"})-[:CO_STARRED_WITH]-(p2) RETURN p2.name即可。所有关系都带weight属性(默认1),为后续推荐算法预留接口。
提示:导入脚本
import_movies.cypher里有一段关键逻辑——对导演和演员姓名做标准化清洗。比如“张艺谋 ”(带空格)、“张艺謀”(繁体)、“zhang yimou”(拼音)统一转为“张艺谋”。我们用Neo4j内置的apoc.text.clean()函数处理,避免因数据脏导致查询失败。这点常被忽略,但实际调试中,80%的“查不到结果”问题都源于姓名不一致。
3.2 自然语言问句解析:从“徐峥主演的喜剧片”到Cypher的翻译器
问答系统的核心不是图谱,而是解析引擎。src/main/java/com/movie/service/QuestionParserService.java是灵魂所在。它不依赖BERT或大模型,而是用规则+词典的轻量方案,兼顾准确率与可解释性。
解析流程分三步:
第一步:关键词抽取。用预置词典匹配,词典存于src/main/resources/dict/目录。director.dict含527个导演名(含别名,如“冯小刚”对应“小刚”),genre.dict含32个类型(“喜剧”“动作”“爱情”等),year.dict含常见年份表述(“2000年代”“千禧年”“上世纪九十年代”)。匹配采用最长词匹配(MMSEG算法简化版),优先识别“张艺谋”而非“张艺”,避免歧义。
第二步:意图识别与槽位填充。根据关键词组合判断意图。例如:
- 含director+genre → FIND_MOVIES_BY_DIRECTOR_AND_GENRE
- 含actor+year_range → FIND_MOVIES_BY_ACTOR_AND_YEAR_RANGE
- 单独actor → FIND_MOVIES_BY_ACTOR
槽位(slot)如director_name="徐峥"、genre_name="喜剧"、year_start=2010、year_end=2020,全部存入QuestionContext对象。
第三步:Cypher模板渲染。每个意图对应一个Cypher模板,存于src/main/resources/cypher/。以FIND_MOVIES_BY_ACTOR_AND_YEAR_RANGE为例:
MATCH (p:Person {name:{actor_name}})<-[:ACTED_IN]-(m:Movie)-[:RELEASED_IN]->(y:Year)
WHERE y.year >= {year_start} AND y.year <= {year_end}
RETURN m.title AS title, m.year AS year, m.rating AS rating
ORDER BY m.rating DESC LIMIT 10
模板用{}占位符,由QuestionParserService注入实际值。这样设计的好处是:学生可以直观看到“问题→意图→模板→查询”的映射,修改一个模板就能改变一类问题的回答逻辑,无需动底层代码。
注意:我们刻意避免在Cypher里用
CONTAINS做模糊匹配(如m.title CONTAINS {keyword}),因为性能差且易误召。所有标题查询都走精确匹配,靠前端搜索框的bindinput事件实时调用/api/search/title接口做前缀匹配,保证体验流畅。
3.3 小程序前端实现:如何让图谱查询结果变成一张张电影卡片?
小程序页面逻辑集中在template/pages/index/index.js。核心交互流程是:用户在搜索框输入→失焦触发onSearchBlur()→调用utils/api.js封装的requestQuestion()方法→后端返回JSON→setData()更新页面数据→WXML循环渲染<view wx:for="{{movies}}" />。
这里有两个关键细节决定用户体验:
一是加载状态管理。index.wxml里有<loading hidden="{{!isLoading}}">查询中...</loading>,index.js中onSearchBlur()开头设this.setData({ isLoading: true }),requestQuestion().then()里设this.setData({ isLoading: false })。看似简单,但很多学生会忘记隐藏加载态,导致用户反复点击后出现多个重叠的“查询中”提示。我们在README.md里专门强调:“务必检查所有异步操作后的setData({ isLoading: false })是否被执行,建议用try...catch包裹网络请求”。
二是结果卡片渲染。<view class="movie-card">里不仅显示片名、年份、评分,还动态渲染“导演”和“主演”标签。这部分逻辑在index.js的formatMovieData()方法里:遍历movie.directors数组(后端返回的导演列表),用wx:for生成<text class="tag" wx:for="{{item.directors}}">{{item}}</text>。难点在于,后端返回的导演名是数组,但小程序WXML不支持直接遍历嵌套数组,必须在JS层预先扁平化。我们实测发现,若在WXML里写{{movie.directors[0]}},当directors为空数组时会报错,所以加了安全访问:{{item.directors.length > 0 ? item.directors[0] : '未知'}}。这个细节在1.png到4.png截图里都能看到——每张卡片右上角都有清晰的导演标签,且空值时显示“未知”而非空白。
4. 本地运行全流程:从零开始,30分钟内跑通问答
4.1 环境准备:四件套清单与版本确认
运行前,请确认本地已安装以下四件套(缺一不可):
| 组件 | 推荐版本 | 验证命令 | 关键说明 |
|---|---|---|---|
| Neo4j Desktop | 1.5.3+ | 打开应用,查看左下角版本号 | 必须用Desktop版(非Server版),因需图形化导入数据;社区版免费,无需License |
| JDK | 8u291 或 11.0.15 | java -version | Spring Boot 2.7.x最低要求JDK 8,JDK 17不兼容 |
| Maven | 3.8.6+ | mvn -v | mvnw脚本已内置,但需确保JAVA_HOME指向正确JDK |
| 微信开发者工具 | Stable 1.06.2304270 | 启动后查看“关于”菜单 | 需登录微信账号,开启“不校验合法域名” |
注意:不要用Neo4j Browser单独启动服务!必须通过Neo4j Desktop创建新项目(Project),再在该项目里启动Graph Database。因为
Neo4j-master/import/下的数据导入脚本,依赖Desktop的图形化导入向导(Import Graph)执行,手动执行LOAD CSV易出编码错误。
4.2 图谱导入:三步完成1267个节点、3942条关系
- 启动Neo4j Desktop → 点击左上角“New Project” → 输入项目名(如
movie-qa)→ 创建; - 在项目页点击“Add Graph” → 选择“Local DBMS” → “Create a new local database” → 数据库名填
movie-db,版本选5.16.0(与pom.xml中neo4j-driver版本一致)→ 创建; - 数据库创建完成后,点击右侧“Manage”按钮 → 切换到“Import Graph”标签页 → 点击“Choose Files”,选择
Neo4j-master/import/csv/目录下的全部.csv文件(movies.csv、persons.csv、genres.csv、years.csv、directed_by.csv等共8个)→ 点击“Import”按钮,等待进度条完成(约90秒)。
导入成功后,在Neo4j Browser(点击数据库旁的“Open Browser”)里执行MATCH (n) RETURN count(n),应返回1267;执行MATCH ()-[r]->() RETURN count(r),应返回3942。若数字不符,大概率是CSV文件编码问题——请用VS Code以UTF-8 BOM格式重新保存所有CSV文件。
4.3 后端启动:Maven打包与端口配置
进入项目根目录(含pom.xml的位置),执行:
# 清理并打包(首次运行较慢,约2分钟)
mvn clean package -DskipTests
# 启动服务(默认端口8080)
java -jar target/movie-qa-service.jar
启动成功后,浏览器访问http://localhost:8080/actuator/health,返回{"status":"UP"}即健康;访问http://localhost:8080/swagger-ui.html可查看所有API文档(/api/question是核心问答接口)。
实操心得:若启动报错
Connection refused: connect,90%是Neo4j服务未启动或配置错误。检查application.yml中spring.neo4j.uri: bolt://localhost:7687是否与Neo4j Desktop中数据库的Bolt地址一致(在数据库“Manage”页的“Connection Settings”里查看)。我们曾遇到学生把地址写成bolt://127.0.0.1:7687,而Neo4j Desktop默认绑定localhost,导致连接失败——这是个典型的“本地环回地址”陷阱。
4.4 小程序调试:从加载到扫码的完整链路
- 打开微信开发者工具 → 点击“导入项目” → 选择
template/目录 → AppID填wx1234567890abcdef(测试专用,不影响功能)→ 导入; - 在开发者工具左侧“编辑器”中,打开
app.js,确认App({})里globalData的baseUrl为http://localhost:8080; - 点击右上角“预览” → 选择“微信扫码预览” → 用真机微信扫描二维码;
- 真机上打开小程序 → 在搜索框输入“周星驰 主演 喜剧” → 点击搜索 → 查看返回的电影卡片。
2.png截图展示的就是这一步:真机界面上,搜索框下方清晰列出《少林足球》《功夫》《西游降魔篇》三张卡片,每张含片名、年份、评分及导演标签。若卡片为空,请按顺序排查:① 后端是否启动;② Neo4j是否运行;③ 小程序app.js中baseUrl是否正确;④ 真机与开发机是否在同一局域网(若用localhost,真机无法访问,此时需将baseUrl改为开发机IP,如http://192.168.1.100:8080)。
5. 常见问题与排查技巧实录:那些踩过的坑,我们都替你趟过了
5.1 问答返回空结果?先查这三个地方
这是新手最常遇到的问题,表面看是“没数据”,实则90%是配置或数据问题。我们整理了高频故障树,按排查顺序排列:
| 现象 | 可能原因 | 快速验证方法 | 解决方案 |
|---|---|---|---|
| 所有问题都返回空数组 | 后端服务未启动或端口被占 | curl http://localhost:8080/actuator/health | 检查java -jar进程是否存活;用netstat -ano \| findstr :8080查端口占用 |
| 特定问题(如“张艺谋导演”)无结果 | Neo4j中无该导演节点 | Neo4j Browser执行MATCH (p:Person {name:"张艺谋"}) RETURN p | 若无返回,说明导入时姓名清洗失败;检查persons.csv中张艺谋的姓名是否为“张艺谋”(无空格/繁体) |
| 问题含年份(如“2010年电影”)无结果 | Year节点未创建或关系未建立 | 执行MATCH (y:Year {year:2010}) RETURN y;再执行MATCH (y:Year {year:2010})<-[:RELEASED_IN]-(m) RETURN count(m) | 若第一步无返回,说明years.csv未导入;若第二步为0,说明released_in.csv中2010年电影ID与movies.csv不匹配 |
独家技巧:在
QuestionParserService.java的parseQuestion()方法末尾,加一行日志log.info("Parsed context: {}", context),重启后端,再提问,就能在控制台看到完整的解析上下文——包括识别出的导演名、年份范围、意图类型。这是定位“为什么没识别出关键词”的最快方式。
5.2 小程序真机无法连接后端?局域网配置指南
微信开发者工具的“预览”功能,在真机上访问localhost是无效的,因为localhost指向真机自身,而非你的开发电脑。解决方案有两个:
方案一(推荐,适合教学演示):改用开发机IP
- 在开发机上,按Win+R输入cmd,执行ipconfig(Windows)或ifconfig(Mac),找到IPv4地址(如192.168.1.100);
- 在小程序app.js中,将globalData.baseUrl从http://localhost:8080改为http://192.168.1.100:8080;
- 确保开发机防火墙允许8080端口入站(Windows:控制面板→Windows Defender防火墙→高级设置→入站规则→新建规则→端口→TCP 8080);
- 真机与开发机连同一WiFi,扫码即可。
方案二(适合多设备联调):用ngrok内网穿透
- 下载ngrok(https://ngrok.com/download),解压后执行ngrok http 8080;
- 复制生成的https://xxx.ngrok.io地址;
- 在小程序app.js中设baseUrl为该地址;
- 注意:免费版ngrok每次重启地址会变,需同步修改小程序代码。
实操心得:我们曾在高校机房部署时发现,部分校园网禁用了非标准端口。此时可修改
application.yml中的server.port: 80(需管理员权限),或改用8081等常用端口,避免被拦截。
5.3 如何快速扩展新功能?三个安全改造入口
这套系统设计时就预留了扩展接口,新增功能无需动核心逻辑:
① 添加新实体类型(如“国家”)
- 步骤1:在Neo4j-master/import/csv/countries.csv中添加国家列表;
- 步骤2:在Neo4j-master/import/cypher/import_countries.cypher中写导入语句;
- 步骤3:在src/main/java/com/movie/entity/Country.java中定义实体类;
- 步骤4:在dict/country.dict中添加国家名词典;
- 步骤5:在QuestionParserService中新增意图识别逻辑。
全程不碰现有代码,符合开闭原则。
② 修改问答样式(如卡片加海报图)
- 只需在template/pages/index/index.wxml中,<view class="movie-card">内添加<image src="{{item.posterUrl}}" mode="aspectFill"/>;
- 在后端Movie实体中加posterUrl字段,并在Cypher查询中RETURN m.posterUrl AS posterUrl;
- 海报图URL可存为相对路径(如/img/posters/1.jpg),放在小程序template/utils/目录下。
③ 接入更准的NLP(如替换为HanLP)
- 替换QuestionParserService中的正则匹配,改为调用HanLP.segment()分词;
- 用HanLP.extractNamedEntity()识别导演、演员;
- 保持原有Cypher模板不变,仅提升前端分词精度。
最后分享一个小技巧:所有截图(
1.png至4.png)都是在Windows 11 + 微信开发者工具Stable版 + Neo4j Desktop 1.5.3环境下录制的。如果你用Mac,注意Neo4j Desktop的CSV导入路径分隔符是/而非\,import_movies.cypher里路径需相应调整。这些细节,正是让一套代码真正“开箱即用”的关键。
简介:直接上手的电影知识问答小程序开发资源,前端用微信小程序原生框架实现交互界面,后端用Neo4j搭建导演、演员、影片、类型、年份等实体及关系构成的知识图谱,支持按自然语言提问获取结构化答案。包里有完整可运行代码——包括小程序pages页面逻辑、utils工具函数、Java后端src模块、Neo4j图谱初始化脚本(Neo4j-master)、小程序项目配置(app.、project.config.)、Maven构建文件(pom.xml、mvnw)、本地调试截图(1.png至4.png)以及清晰的README操作指南和LICENSE授权说明。所有模块已在真实环境验证:启动本地Neo4j服务后,小程序扫码即可连接后端完成问答流程,无需二次开发或环境魔改。适合高校课程设计、毕业设计快速落地,也适合作为知识图谱入门+小程序前后端联调的教学案例,覆盖从数据建模、图谱导入、API对接到界面呈现的全流程。

331

被折叠的 条评论
为什么被折叠?



