knowledgeService.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. package service
  2. import (
  3. cm "app.yhyue.com/moapp/jybase/common"
  4. . "app.yhyue.com/moapp/jybase/encrypt"
  5. elastic "app.yhyue.com/moapp/jybase/esv1"
  6. . "bp.jydev.jianyu360.cn/SocialPlatform/knowledgeBase/entity"
  7. ki "bp.jydev.jianyu360.cn/SocialPlatform/knowledgeBase/rpc/knowledge/init"
  8. "bp.jydev.jianyu360.cn/SocialPlatform/knowledgeBase/rpc/knowledge/knowledgeclient"
  9. "bp.jydev.jianyu360.cn/SocialPlatform/knowledgeBase/rpc/knowledge/util"
  10. "database/sql"
  11. "fmt"
  12. "github.com/zeromicro/go-zero/core/logx"
  13. "log"
  14. "strconv"
  15. "time"
  16. )
  17. type KnowledgeService struct{}
  18. var (
  19. Index = "smart_new"
  20. Type = "smart"
  21. )
  22. // KnowledgeAdd 添加问题
  23. func (k *KnowledgeService) KnowledgeAdd(param *knowledgeclient.AddRequest, segment string) (bool, string) {
  24. //先查找知识库Id
  25. query := map[string]interface{}{"status": 1, "appid": param.AppId, "ent_id": param.EntId}
  26. datalist := Mysql.Find(util.KNOWLEDGE, query, "id", "", -1, -1)
  27. if datalist != nil && *datalist != nil && len(*datalist) > 0 {
  28. //问题进行分词
  29. keywords := ""
  30. keywordsArr := util.HanlpGetNormalWords(param.Question, segment)
  31. if len(keywordsArr) != 0 {
  32. for _, val := range keywordsArr {
  33. keywords += val + " "
  34. }
  35. }
  36. if keywords == "" {
  37. keywords = param.Question
  38. }
  39. createPerson := param.EntUserId
  40. var answerId int64
  41. nowTime := time.Now().Local().Format(util.DateFullLayout)
  42. fool := Mysql.ExecTx("添加知识", func(tx *sql.Tx) bool {
  43. //插入答案
  44. answerData := map[string]interface{}{
  45. "knowledge_id": (*datalist)[0]["id"],
  46. "status": 1,
  47. "create_time": nowTime,
  48. "update_time": nowTime,
  49. "create_person": createPerson,
  50. "content": param.Answer,
  51. }
  52. answerId = Mysql.Insert(util.ANSWER, answerData)
  53. //插入问题
  54. questionData := map[string]interface{}{
  55. "answer_id": answerId,
  56. "content": param.Question,
  57. "keywords": keywords,
  58. }
  59. questionId := Mysql.Insert(util.QUESTION, questionData)
  60. return answerId > 0 && questionId > 0
  61. })
  62. if fool {
  63. //插入es
  64. knowledge := map[string]interface{}{
  65. "knowledgeId": (*datalist)[0]["id"],
  66. "status": 1,
  67. "createTime": time.Now().Unix(),
  68. "createPerson": createPerson,
  69. "answer": param.Answer,
  70. "question": param.Question,
  71. "keywords": keywords,
  72. "answerId": answerId,
  73. "entId": param.EntId,
  74. }
  75. b := elastic.Save(Index, Type, knowledge)
  76. if !b {
  77. return false, "es 保存失败"
  78. }
  79. questionVector, err := util.EncodeVector(param.Question)
  80. if err != nil {
  81. return false, "获取 向量失败 :" + err.Error()
  82. }
  83. // 存入向量库
  84. //插入es
  85. knowledgeV := map[string]interface{}{
  86. "mod_time": time.Now().Unix(),
  87. "answer": param.Answer,
  88. "question": param.Question,
  89. "id": answerId,
  90. "entId": param.EntId,
  91. "questionVector": questionVector,
  92. }
  93. if !ESV7.Save(ESV7Index, ESV7Type, knowledgeV) {
  94. logx.Error("知识库添加向量失败:", knowledgeV)
  95. }
  96. return b, ""
  97. }
  98. return fool, "插入mysql出错"
  99. }
  100. return false, "租户不存在"
  101. }
  102. // KnowledgeEdit 编辑问题
  103. func (k *KnowledgeService) KnowledgeEdit(param *knowledgeclient.KnowledgeEditReq, segment string) (ok bool) {
  104. ok = false
  105. //获取问题分词
  106. keywords := ""
  107. keywordsArr := util.HanlpGetNormalWords(param.Question, segment)
  108. logx.Info("keywordsArr", keywordsArr)
  109. if len(keywordsArr) != 0 {
  110. for _, val := range keywordsArr {
  111. keywords += val + " "
  112. }
  113. }
  114. if keywords == "" {
  115. keywords = param.Question
  116. }
  117. //通过entUserId获取创建人名称
  118. /*req := &usercenter.EntUserReq{
  119. EntId: param.EntId,
  120. EntUserId: param.EntUserId,
  121. AppId: param.AppId,
  122. }
  123. resp, err := UserCenterLib.GetEntUserInfo(context.Background(), req)
  124. if resp.ErrorCode != 0 {
  125. logx.Info("查询用户中台创建人信息失败", param.EntId, param.EntUserId, "err:", err)
  126. return ok
  127. }*/
  128. createPerson := param.EntUserId
  129. fool := Mysql.ExecTx("编辑问题、答案", func(tx *sql.Tx) bool {
  130. //修改答案
  131. answerUpdate := map[string]interface{}{
  132. "update_time": time.Now().Local().Format(util.DateFullLayout),
  133. "content": param.Answer,
  134. }
  135. ok1 := Mysql.UpdateByTx(tx, util.ANSWER, map[string]interface{}{"id": param.AnswerId}, answerUpdate)
  136. //修改问题
  137. questionUpdate := map[string]interface{}{
  138. "content": param.Question,
  139. "keywords": keywords,
  140. }
  141. ok2 := Mysql.UpdateByTx(tx, util.QUESTION, map[string]interface{}{"answer_id": param.AnswerId}, questionUpdate)
  142. return ok1 && ok2
  143. })
  144. if fool {
  145. query := `{"query":{"bool":{"must":[{"term":{"answerId":"` + strconv.Itoa(int(param.AnswerId)) + `"}}],"must_not":[],"should":[]}},"from":0,"size":10,"sort":[],"facets":{}}`
  146. //修改es数据
  147. newKnowledge := map[string]interface{}{
  148. "knowledgeId": param.KnowledgeId,
  149. "status": 1,
  150. "createTime": time.Now().Unix(),
  151. "createPerson": createPerson,
  152. "answer": param.Answer,
  153. "question": param.Question,
  154. "keywords": keywords,
  155. "answerId": param.AnswerId,
  156. "entId": param.EntId,
  157. }
  158. ok1 := elastic.Del(Index, Type, query)
  159. ok2 := elastic.Save(Index, Type, newKnowledge)
  160. // 查询出来
  161. queryByAid := fmt.Sprintf(`{
  162. "query": {
  163. "bool": {
  164. "must": [
  165. {
  166. "term": {
  167. "id": %v
  168. }
  169. }
  170. ]
  171. }
  172. },
  173. "size": 1
  174. }`, param.AnswerId)
  175. rs := ESV7.Get(ESV7Index, ESV7Type, queryByAid)
  176. _id := ""
  177. if rs != nil && len(*rs) > 0 {
  178. _id = cm.InterfaceToStr((*rs)[0]["_id"])
  179. }
  180. questionVector, err := util.EncodeVector(param.Question)
  181. if err != nil {
  182. log.Println("001 获取 向量失败 :" + err.Error())
  183. return false
  184. }
  185. // 存入向量库
  186. //插入es
  187. knowledgeV := map[string]interface{}{
  188. "mod_time": time.Now().Unix(),
  189. "answer": param.Answer,
  190. "question": param.Question,
  191. "id": param.AnswerId,
  192. "entId": param.EntId,
  193. "questionVector": questionVector,
  194. }
  195. if _id != "" {
  196. knowledgeV["_id"] = _id
  197. }
  198. if !ESV7.Save(ESV7Index, ESV7Type, knowledgeV) {
  199. logx.Error("知识库添加向量失败:", knowledgeV)
  200. }
  201. return ok1 && ok2
  202. }
  203. return ok
  204. }
  205. // KnowledgeList 问题列表
  206. func (k *KnowledgeService) KnowledgeList(param *knowledgeclient.ListRequest) *knowledgeclient.ListData {
  207. var knowledgeList knowledgeclient.ListData
  208. var data []*knowledgeclient.KnowledgeEntity
  209. countSql := fmt.Sprintf("SELECT COUNT(b.id) FROM %s a LEFT JOIN %s b ON a.id = b.knowledge_id LEFT JOIN %s c ON b.id = c.answer_id WHERE b.`status` =1 and a.ent_id=%d", util.KNOWLEDGE, util.ANSWER, util.QUESTION, param.EntId)
  210. count := Mysql.CountBySql(countSql)
  211. if count > 0 {
  212. //列表数据
  213. sql1 := fmt.Sprintf("SELECT b.content as answer,c.content as question,b.id,b.knowledge_id FROM %s a LEFT JOIN %s b ON a.id = b.knowledge_id LEFT JOIN %s c ON b.id = c.answer_id WHERE b.`status` =1 and a.ent_id=? order by b.update_time desc limit ?,?", util.KNOWLEDGE, util.ANSWER, util.QUESTION)
  214. datalist := Mysql.SelectBySql(sql1, param.EntId, (param.PageIndex-1)*param.PageSize, param.PageSize)
  215. if datalist != nil && *datalist != nil && len(*datalist) > 0 {
  216. for _, value := range *datalist {
  217. knowledge := knowledgeclient.KnowledgeEntity{}
  218. knowledge.Answer = cm.ObjToString(value["answer"])
  219. knowledge.Question = cm.ObjToString(value["question"])
  220. knowledge.AnswerId = cm.Int64All(value["id"])
  221. knowledge.KnowledgeId = cm.Int64All(value["knowledge_id"])
  222. data = append(data, &knowledge)
  223. }
  224. }
  225. knowledgeList.Total = count
  226. knowledgeList.Data = data
  227. }
  228. return &knowledgeList
  229. }
  230. // KnowledgeInfo 问题详情
  231. func (k *KnowledgeService) KnowledgeInfo(answerId int64) (data *knowledgeclient.KnowledgeEntity, ok bool) {
  232. //util.ANSWER,util.QUESTION
  233. sql1 := fmt.Sprintf("SELECT b.content as answer,c.content as question,b.id,b.knowledge_id FROM %s b LEFT JOIN %s c ON b.id = c.answer_id WHERE b.`status` =1 AND b.id = %d", util.ANSWER, util.QUESTION, answerId)
  234. datalist := Mysql.SelectBySql(sql1)
  235. if datalist != nil && *datalist != nil && len(*datalist) > 0 {
  236. knowledge := knowledgeclient.KnowledgeEntity{}
  237. knowledge.Answer = cm.ObjToString((*datalist)[0]["answer"])
  238. knowledge.Question = cm.ObjToString((*datalist)[0]["question"])
  239. knowledge.AnswerId = cm.Int64All((*datalist)[0]["id"])
  240. knowledge.KnowledgeId = cm.Int64All((*datalist)[0]["knowledge_id"])
  241. return &knowledge, true
  242. }
  243. return nil, false
  244. }
  245. // KnowledgeDel 删除问题
  246. func (k *KnowledgeService) KnowledgeDel(answerId int64) (ok bool) {
  247. ok = false
  248. //修改答案
  249. answerUpdate := map[string]interface{}{
  250. "update_time": time.Now().Local().Format(util.DateFullLayout),
  251. "status": 0,
  252. }
  253. fool := Mysql.Update(util.ANSWER, map[string]interface{}{"id": answerId}, answerUpdate)
  254. if fool {
  255. //删除es数据
  256. query := `{"query":{"bool":{"must":[{"term":{"answerId":"` + strconv.Itoa(int(answerId)) + `"}}],"must_not":[],"should":[]}},"from":0,"size":1,"sort":[],"facets":{}}`
  257. ok = elastic.Del(Index, Type, query)
  258. queryByAid := fmt.Sprintf(`{
  259. "query": {
  260. "bool": {
  261. "must": [
  262. {
  263. "term": {
  264. "id": %v
  265. }
  266. }
  267. ]
  268. }
  269. },
  270. "size": 1
  271. }`, answerId)
  272. rs := ESV7.Get(ESV7Index, ESV7Type, queryByAid)
  273. if rs != nil && len(*rs) > 0 {
  274. _id := cm.InterfaceToStr((*rs)[0]["_id"])
  275. if !ESV7.DelById(ESV7Index, ESV7Type, _id) {
  276. logx.Error("删除向量库失败:", _id, answerId)
  277. }
  278. }
  279. }
  280. return ok
  281. }
  282. // FindAnswer 根据问题推荐一个答案
  283. func (k *KnowledgeService) FindAnswer(param *knowledgeclient.FindAnswerReq, addr, index, segment string) *knowledgeclient.Question {
  284. var question knowledgeclient.Question
  285. robotEntId := SE.Decode4Hex(param.RobotEntId)
  286. //组装es query
  287. //query := util.DSL4SmartResponse(param.Question, robotEntId, int(param.Type), addr, index, segment)
  288. query := util.GetAnswerQueryStr(param.Question, robotEntId, 1, ki.C.MinScore)
  289. logx.Info("query:", query)
  290. if query != "" {
  291. res := ESV7.Get(ESV7Index, ESV7Type, query)
  292. if res != nil && len(*res) > 0 {
  293. data := (*res)[0]
  294. question.Answer = cm.ObjToString(data["answer"])
  295. question.Question = cm.ObjToString(data["question"])
  296. }
  297. }
  298. return &question
  299. }
  300. // RecommendAnswer 根据问题推荐三个答案
  301. func (k *KnowledgeService) RecommendAnswer(param *knowledgeclient.FindAnswerReq, segment string, recommendQuestionCount int) []*knowledgeclient.Question {
  302. var (
  303. //keyWords = ""
  304. //searchField = `"answer","question"`
  305. answers []*knowledgeclient.Question
  306. )
  307. robotEntId := SE.Decode4Hex(param.RobotEntId)
  308. ////根据问题进行分词
  309. //keywordsArr := util.HanlpGetNormalWords(param.Question, segment)
  310. //logx.Info("keywordsArr", keywordsArr)
  311. //if len(keywordsArr) != 0 {
  312. // for _, val := range keywordsArr {
  313. // keyWords += val + " "
  314. // }
  315. //}
  316. //if keyWords == "" {
  317. // keyWords = param.Question
  318. //}
  319. ////logx.Info("entId:", SE.Decode4Hex(param.RobotEntId))
  320. //var query = util.DSL4SearchByKwsOrid(keyWords, param.RobotEntId, 0)
  321. limit := 3
  322. if param.ReqSource == 1 {
  323. limit = recommendQuestionCount
  324. }
  325. //res := elastic.GetAllByNgram(Index, Type, query, "", "", searchField, 0, limit, 0, false)
  326. query := util.GetAnswerQueryStr(param.Question, robotEntId, limit, ki.C.MinScore)
  327. logx.Info("query:", query)
  328. res := ESV7.Get(ESV7Index, ESV7Type, query)
  329. if res != nil && len(*res) > 0 {
  330. for _, val := range *res {
  331. answers = append(answers, &knowledgeclient.Question{
  332. Question: cm.ObjToString(val["question"]),
  333. Answer: cm.ObjToString(val["answer"]),
  334. })
  335. }
  336. log.Println("推荐答案:", answers)
  337. }
  338. return answers
  339. }