# ps-kg-server **Repository Path**: delphi_xk/ps-kg-server ## Basic Information - **Project Name**: ps-kg-server - **Description**: knowledge graph springboot application service - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2019-07-08 - **Last Updated**: 2022-03-23 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ps-kg-server 图数据库RESTful API,主要是图相关信息的查询接口,返回JSON格式字符串 配置文件位于`resources/server.properties`文件 ## 部署说明 * `neo4j_3.5.5.tar`为docker镜像文件,使用`docker load`导入即可,注意版本号3.5.5 * `neo4j-data.tar.gz`为图数据库docker镜像启动时需要的数据挂载文件,根据实际解压目录,修改`docker run -v`参数 ```bash docker run --name neo4j_db -p 7474:7474 -p 7687:7687 \ -v /home/hyzs/neo4j/data:/data \ -v /home/hyzs/neo4j/logs:/logs \ -v /home/hyzs/neo4j/import:/import \ -v /home/hyzs/neo4j/plugins:/plugins \ -e NEO4J_apoc_export_file_enabled=true \ -e NEO4J_apoc_import_file_enabled=true \ -e NEO4J_apoc_import_file_use__neo4j__config=true \ -e NEO4J_dbms_security_procedures_unrestricted=apoc.\\\*,algo.\\\* \ -e NEO4J_dbms_memory_pagecache_size=8G \ -e NEO4J_dbms_memory_heap_init__size=8G \ -e NEO4J_dbms_memory_heap_max__size=8G \ -tid neo4j:3.5.5 ``` * `server.jar`为服务后台,使用 ``` java -jar server.jar --spring.application.json='{"graph.url":"bolt://172.16.121.3:7687", "mysql.url": "jdbc:mysql://172.16.18.28:3306/judicial_documents?characterEncoding=utf-8"}' ``` 启动即可, [源码地址](http://172.16.120.120/25177/ps-kg-server) ## 相关接口 ### 1. 获取相关判决书数据 * URL:*http://{ip}:8080*/getSimJudgements * 输入:json格式参数, ` {"topK": "10", "content": "(意见书正文内容)..."}` * 例子:http://172.16.121.3:8080/getSimJudgements * 返回结果为json列表,其中similarity代表相似度,Judgement代表相关判决书 ```json [ { "similarity": "0.5", "Judgement": { "pub_date": "2016-05-24", "create_time": "2019-07-09 16:42:21.0", "judgement_date": "2004-06-18", "case_type": "", "trial_procedures": "", "court_name": "嘉善县人民法院", "title": "唐某犯盗窃罪一审刑事判决书", "doc_id": "02df90e0-6717-4f98-ab0b-e191741e2028", "case_num": "", "url": "http://wenshu.court.gov.cn/CreateContentJS/CreateContentJS.aspx?DocID=02df90e0-6717-4f98-ab0b-e191741e2028" } }, { "similarity": "0.5", "Judgement": { "pub_date": "2016-05-24", "create_time": "2019-07-09 17:23:14.0", "judgement_date": "2003-09-29", "case_type": "", "trial_procedures": "", "court_name": "嘉善县人民法院", "title": "闫某犯盗窃罪一审刑事判决书", "doc_id": "16ef70e5-cbcd-40d9-9773-5c6b007dbf05", "case_num": "", "url": "http://wenshu.court.gov.cn/CreateContentJS/CreateContentJS.aspx?DocID=16ef70e5-cbcd-40d9-9773-5c6b007dbf05" } }, ...... ] ``` ### 2. 根据(部分匹配)法条名称,获取法条信息 * URL:*http://{ip}:8080*/getLawByName * 输入:*http://{ip}:8080*/getLawByName?name=XXX * 例子:http://172.16.121.3:8080/getLawByName?name=刑法 * 返回结果为json列表,其中law代表每个法条信息。 ```json [ { "law": { "name": "中华人民共和国刑法", "level": 0, "content": "中华人民共和国刑法", "belongs_law": "" } }, { "law": { "name": "中华人民共和国刑法第一条", "level": 2, "content": "为了惩罚犯罪,保护人民,根据宪法,结合我国同犯罪作斗争的具体经验及实际情况,制定本法。", "belongs_law": "第一编总则第一章刑法的任务、基本原则和适用范围" } }, ... ``` ### 3. 根据(准确匹配)法条名称,获取整体法条树结构信息 * URL:*http://{ip}:8080*/getLawTree * 输入:*http://{ip}:8080*/getLawTree?name=XXX * 例子:http://172.16.121.3:8080/getLawTree?name=中华人民共和国刑法 * 返回结果为json列表,其中law代表法条信息,children_laws代表子法条的列表 ```json { "law": { "name": "中华人民共和国刑法", "level": 0, "content": "中华人民共和国刑法", "belongs_law": "" }, "children_laws": [ {"law": ..., "children_laws": ...}, {"law": ..., "children_laws": ...}, ... ] } ``` ### 4. 根据(起诉)意见书正文,获取法条 * URL:*http://{ip}:8080*/getJudgementLaws * 输入:json格式参数, ` {"content": "(意见书正文内容)..."}` * 例子:http://172.16.121.3:8080/getJudgementLaws * 返回结果为json列表,其中law代表正文中提到的法条信息 ```json [ { "law": { "name": "中华人民共和国刑法第二百六十四条", "level": 2, "belongs_law": "第五章侵犯财产罪", "content": "盗窃公私财物,数额较大或者多次盗窃的,处三年以下有期徒刑、拘役或者管制,并处或者单处罚金;数额巨大或者有其他严重情节的,处三年以上十年以下有期徒刑,并处罚金;数额特别巨大或者有其他特别严重情节的,处十年以上有期徒刑或者无期徒刑,并处罚金或者没收财产;有下列情形之一的,处无期徒刑或者死刑,并处没收财产:(一)盗窃金融机构,数额特别巨大的;(二)盗窃珍贵文物,情节严重的。" } }, ... ] ``` ### 5. 根据输入法条,返回关联法条 * URL:*http://{ip}:8080*/getRelativeLaws * 输入:*http://{ip}:8080*/getRelativeLaws?names=XXX,names可输入多个法条,用`,`分隔,topK为返回结果条数 * 例子:http://172.16.121.3:8080/getRelativeLaws?names=中华人民共和国刑法第二百六十四条&topK=10 * 返回结果为json列表,其中law代表正文中提到的法条信息 ```json [ { "score": "0.02821405202371352", "relativeLaw": { "name": "中华人民共和国刑法第六十七条", "level": 2, "belongs_law": "第三节自首和立功", "content": "犯罪以后自动投案,如实供述自己的罪行的,是自首。对于自首的犯罪分子,可以从轻或者减轻处罚。其中,犯罪较轻的,可以免除处罚。被采取强制措施的犯罪嫌疑人、被告人和正在服刑的罪犯,如实供述司法机关还未掌握的本人其他罪行的,以自首论。" } }, { "score": "0.0206561409006234", "relativeLaw": { "name": "中华人民共和国刑法第二十五条", "level": 2, "belongs_law": "第三节共同犯罪", "content": "共同犯罪是指二人以上共同故意犯罪。二人以上共同过失犯罪,不以共同犯罪论处;应当负刑事责任的,按照他们所犯的罪分别处罚。" } }, ... ] ``` ### 6. 根据输入ID,返回判决书正文数据 * URL:*http://{ip}:8080*/getJudgementContent * 输入:GET方法,*http://{ip}:8080*/getJudgementContent?doc_id=XXX * 例子:http://172.16.121.3:8080/getJudgementContent?doc_id=00002417-a768-456c-94a7-e757648c9c06 * 返回结果为json对象,其中doc_id代表判决书ID,content代表正文。 ### 7. 根据输入ID列表,批量返回判决书正文数据列表 * URL:*http://{ip}:8080*/getJudgementContentBatch * 输入:POST方法,json格式参数, ` {"doc_ids": ["", "", ...] }` * 例子:http://172.16.121.3:8080/getJudgementContentBatch, ```json { "doc_ids": ["00002417-a768-456c-94a7-e757648c9c06", "000041f6-4eb9-4b10-941a-0cf5f56ba32f", "00011bcb-eedf-42d8-96a6-a85800a31c11"] } ``` * 返回结果为json列表,其中doc_id代表判决书ID,content代表正文。 ### 8. 根据输入文本和标签类别名,生成对应子标签分数 * URL:*http://{ip}:8080*/queryContentLabels * 输入:POST方法,json格式参数, ` {"label_name": "XXX", "content": "...", topK: "10" }` * content为正文内容,label_name参数为指定的标签类别,只能支持以下几种: - WXJS_behavior, JTZS_behavior - XXZS_circums, XXZS_harm, XXZS_behavior - penalty_heavier, penalty_ease, penalty_ease_circumstance - all_labels(全部标签) ### 9. 根据输入文本和标签列表名,生成对应标签的码值(True, False) * URL:*http://{ip}:8080*/queryContentLabelArray * 输入:POST方法,json格式参数, ` {"labels": ["AAA", "BBB"], "content": "..." }` * content为正文内容,labels参数为指定的标签列表,只能支持以下几种: |类别|标签名| |---|---| |isXXZS_behavior|isXXZS_beat, isXXZS_chase, isXXZS_intercept, isXXZS_abuse, isXXZS_threaten, isXXZS_damage, isXXZS_occupy, isXXZS_chaos| |isXXZS_harm |isXXZS_harm_value, isXXZS_harm_one, isXXZS_harm_two, isXXZS_harm_insane, isXXZS_harm_suicide | |isXXZS_circumstance |isXXZS_cir_beat_multi, isXXZS_cir_beat_arm, isXXZS_cir_beat_psychotic, isXXZS_cir_beat_disabled, isXXZS_cir_beat_beggar, ...| |isJTZS_behavior |isJTZS_heavilyHarm, isJTZS_dead, isJTZS_asset, isJTZS_escape, isJTZS_escapeDead | |isWXJS_behavior |isWXJS_chase, isWXJS_alcohol, isWXJS_danger, isWXJS_unlicensed, isWXJS_escape | |isZSFMYSZZDP_circumstance |is_ZSFMYSZZDP_cir_gun, is_ZSFMYSZZDP_cir_boom, is_ZSFMYSZZDP_cir_dead, ... | |isZSFMYSZZDP_behavior |is_ZSFMYSZZDP_behavior_smuggle, is_ZSFMYSZZDP_behavior_sale, is_ZSFMYSZZDP_behavior_make, is_ZSFMYSZZDP_behavior_transport, ... | |isMeasure_heavier |heavier_recidivism, heavier_others | |isMeasure_ease |ease_surrender, ease_confess, ease_well, ... | |isMeasure_easeCir |easeCircum_surrender, easeCircum_confess, ... | ### 10. 查询支持标签(label) * GET方法,无参数, URL:*http://{ip}:8080*/availableLabels ```json { "labels": ["isWXJS_chase", "isWXJS_alcohol", ...] } ``` ### 11. 根据对应标签,置信度大于0.1为阈值,返回对应标签的码值(True、False) * URL:*http://{ip}:8080*/GJqueryContentLabels * 输入:POST方法,json格式参数, ` {"label_name": ["XXX", "AAA", "BBB"], "content": "..." }` * 支持标签: - gj_penalty_ease, gj_penalty_heavier, - gj_ease_well, gj_ease_forgive - gj_isWXJS_unlicensed, gj_isWXJS_alcohol, gj_isWXJS_overman, gj_isWXJS_escape - gj_isJTZS_heavilyHarm, gj_isJTZS_dead, gj_isJTZS_asset, gj_isJTZS_escape, - gj_ZSFMYSZZDP_smuggle, gj_ZSFMYSZZDP_sale, gj_ZSFMYSZZDP_transport, gj_ZSFMYSZZDP_underage, gj_ZSFMYSZZDP_international, gj_ZSFMYSZZDP_principal, gj_ZSFMYSZZDP_arm, gj_ZSFMYSZZDP_make, gj_ZSFMYSZZDP_pregnant, gj_ZSFMYSZZDP_rehab, gj_ZSFMYSZZDP_express * 例子:http://172.16.121.3:8080/GJqueryContentLabels ```json { "label_name": ["gj_penalty_ease", "gj_penalty_heavier", "gj_ease_well", "gj_ZSFMYSZZDP_underage", "gj_ZSFMYSZZDP_international", "gj_isJTZS_escape", "gj_isWXJS_unlicensed", "gj_isWXJS_alcohol", "gj_ZSFMYSZZDP_smuggle", "gj_ZSFMYSZZDP_sale"], "content": "何某危险驾驶罪一审刑事判决书浙江省平湖市人民法院,刑事判决书,(2011)嘉平刑初字第611号,公诉机关平湖市人民检察院。,被告人何某,职工。因本案,于2011年9月21日被平湖市公安局取保候审。,平湖市人民检察院以平检刑诉(2011)609号起诉书指控被告人何某犯危险驾驶罪,于2011年10月24日向本院提起公诉。本院于同日受理,并依法适用简易程序,实行独任审判,公开开庭审理了本案。被告人何某到庭参加诉讼。现已审理终结。,公诉机关指控:,2011年8月22日22时许,被告人何某饮酒后驾驶川y×××××二轮摩托车由东向西行驶至平湖市独山港镇丰荡村南侧路段时撞到路边围墙,造成被告人何某本人受伤、车辆损坏的交通事故。,经嘉兴市公安司法鉴定中心鉴定:被告人何某血液中含有乙醇成份,含量为1.26mg/ml。,另查明:被告人何某血液中的乙醇含量已超过0.8mg/ml的醉酒驾驶机动车的标准。,上述犯罪事实,被告人何某在开庭审理过程中亦无异议,且有证人证言、机动车驾驶证及行驶证复印件、车辆信息、交通事故车辆技术检验报告、交通事故照片及说明、现场勘查笔录、交通事故认定书、提取血样登记表、理化检验报告、案发经过、身份证明等证据予以证实,足以认定。,本院认为,被告人何某在道路上醉酒驾驶机动车,并发生交通事故,其行为已构成危险驾驶罪。公诉机关指控的罪名成立,应予支持。被告人何某能如实供述自己的犯罪事实,依法可以从轻处罚。据此,依照《中华人民共和国刑法》第一百三十三条之一、第六十七条第三款之规定,判决如下:,被告人何某犯危险驾驶罪,判处拘役一个月,并处罚金1000元。,刑期从判决执行之日起计算;罚金款限本判决生效后十日内缴纳。,如不服本判决,可在接到判决书的第二日起十日内,通过本院或者直接向浙江省嘉兴市中级人民法院提出上诉。书面上诉的,应当提交上诉状正本一份,副本二份。,审判员李登峰,二〇一一年十一月四日,书记员俞佳伦" } ``` ## Lucene相关 ### Lucene评分机制的概念模型 * Lucene的默认评分机制是基于VSM(Vector Space Model)的TFIDF算法 * Lucene的评分是计算在向量空间中文档与查询之间的余弦相似度(Cosine Similarity) * 原始的cosine-similarity计算方法: \\[ \text{cos-sim}(q,d) = \frac{V(q) \cdot V(d)}{|V(q)| |V(d)|} \\] * \\(V(q) \cdot V(d)\\)是向量的内积,\\( |V(q)| |V(d)| \\) 是向量的欧几里得范数 ### Lucene的一些优化,比如: - 规范化(Normalizing)V(d)成单位向量会去掉全部的文档长度信息。 `doc-len-norm(d)`会比单位向量更长。 - 建立索引时,用户可以使用参数` doc-boost(d)`指定某些更重要的文档。 - Lucene是基于域的(field based),也可以根据不同域来指定加权(field boost)。 - Lucene可以指定查询的加权,设置参数`query-boost(q)`。 ### Lucene的概念分数计算公式: \\[ score(q,d) = \text{query-boost}(q) \cdot \frac{V(q) \cdot V(d)}{|V(q)|} \cdot \text{doc-len-norm}(d) \cdot \text{doc-boost}(d) \\] lucene在实际实现中为了效率上的优化,提前进行了一些计算: - Query-boost是在查询开始之前就已知的。 - Query的范数`|V(q)|`也是提前计算的,分数都需要与其相乘,因此是不会影响检索排序结果的。为了在相同文档的不同查询的分数直接进行比较,因此乘以查询向量的范数是有必要的。 ### Lucene的实际分数计算公式: \\[ score(q,d) = coord(q,d) \cdot queryNorm(q) \cdot \sum (tf(\text{t in d}) \cdot idf(t)^2 \cdot t.getBoost() \cdot norm(t,d)) \\] 1. *tf(t in d)*指的是词项的频率, \\[ \text{tf(t in d)} = freq^\frac{1}{2} \\] 2. idf(t)是逆文档频率, \\[ idf(t) = 1 + log( \frac{numDocs}{docFreq+1} ) \\] 3. coord(q,d)是查询与文档的相关系数,如`query = a AND b AND c`,但文档中只出现a词项,则相关系数为1/3。 4. queryNorm(q)计算: \\[ queryNorm(q) = queryNorm(sumOfSqueryWeights) = \frac{1}{sumOfSquaredWeight^\frac{1}{2}} \\] 5. sumOfSquaredWeights: \\[ sumOfSquaredWeights = q.getBoost()^2 \cdot \sum_{\text{t in q}}(idf(t) \cdot t.getBoost)^2 \\] 6. `norm(t,d)`需要考虑域的加权和长度范数,词项短的域会贡献更高的分数。当一篇文档被索引时,这些参数都会被计算好。查询时已不能修改这些值,如需修改,考虑使用其他*Similarity*计算方法。 \\[ norm(t,d) = lengthNorm \cdot \prod_\text{f in d as t} f.boost() \\] ## 服务启动说明 - 服务基于SpringBoot开发,数据库相关配置在`resources/application.yml`内。 - RawDataService提供查询原始数据表数据,GraphService提供图结构相关查询及类案相关接口,FulltextService提供全文检索分类相关接口。 ## ES索引数据处理 ### 1. 安装ES分词插件 - 本项目基于ES-7.3.1开发,完成ES常规配置后,安装smart-cn和analysis-ik插件 ```bash ./bin/elasticsearch-plugin install analysis-smartcn ./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.3.1/elasticsearch-analysis-ik-7.3.1.zip ``` - analysis-ik可以配置自定义词典,配置文件位于`$ES_HOME/config/analysis-ik/IKAnalyzer.cfg.xml`。 ### 2. 建立索引 - `EsBasicTest.testRebuildIndices`建立judgement索引,索引相关配置在resources/JudgementSettings_v3.json中设置。 - `indexName`为索引名称,`testRebuildIndices`会检测是否已有该索引,如已经存在,会自动删除并重建。 ### 3. 导入索引数据 - `EsBulkInsert.main`会执行批量导入索引正文数据的过程,`indexName`为指定索引名称。 - `EsBulkInsert.bulkInsert`中设置查询SQL的起始位置。 ### 4. 测试接口 - `EsService.queryContentLabels`会查询输入文本对应的标签分类下的label的分数,可使用"all_labels"查询全部标签,`topK`为分数排名的前K项。 - `EsService.queryContentLabelByCrimes`会查询输入文本的对应标签的码值(true/false),`crimes`为对应标签的数组。 - `EsBasicTest.testQueryLabels2`和`EsBasicTest.testQueryLabels3`为对应测试代码。 - `src/test/resources/testDoc.txt`为对应测试文本。 ### 5. 打包docker服务镜像 - Dockerfile ```bash FROM openjdk:8-jdk-alpine VOLUME /tmp COPY ps-kg-server-0.0.1-SNAPSHOT.jar app.jar ENTRYPOINT ["java", "-jar","/app.jar"] ``` - 相关命令 ``` docker build -t neo4j-server:1.0 . docker save -o neo4j-server.tar neo4j-server:1.0 docker load -i neo4j-server.tar docker run --name neo4j-server -p 8080:8080 -e spring.application.json='{"graph.url":"bolt://172.16.119.31:7687", "mysql.url": "jdbc:mysql://172.16.18.28:3306/judicial_documents?characterEncoding=utf-8"}' -tid neo4j-server:1.0 ```