From 9de43d0d09c10b53b74f2d0af0cd0bbd4c9c2530 Mon Sep 17 00:00:00 2001 From: Havoc412 <2993167370@qq.com> Date: Wed, 13 Nov 2024 17:47:16 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=86=95finish=20half=20knowledge=20ES?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/model_es/animal.go | 1 + app/model_es/knowledge.go | 144 ++++++++++++++++++++++++++++++++++++++ test/es/encounter_test.go | 3 +- test/es/knowledge_test.go | 119 +++++++++++++++++++++++++++++++ 4 files changed, 265 insertions(+), 2 deletions(-) create mode 100644 app/model_es/animal.go create mode 100644 app/model_es/knowledge.go create mode 100644 test/es/knowledge_test.go diff --git a/app/model_es/animal.go b/app/model_es/animal.go new file mode 100644 index 0000000..d37a815 --- /dev/null +++ b/app/model_es/animal.go @@ -0,0 +1 @@ +package model_es diff --git a/app/model_es/knowledge.go b/app/model_es/knowledge.go new file mode 100644 index 0000000..5b51820 --- /dev/null +++ b/app/model_es/knowledge.go @@ -0,0 +1,144 @@ +package model_es + +import ( + "bytes" + "catface/app/global/variable" + "context" + "encoding/json" + "fmt" + "math/rand" + "strings" + "time" + + "github.com/elastic/go-elasticsearch/v8/esapi" +) + +func CreateKnowledgeESFactory() *Knowledge { + return &Knowledge{} +} + +type Knowledge struct { + Id int32 `json:"id"` // TIP int64 会炸 ES 的 ‘integer’ + Dirs []string `json:"dirs"` + Title string `json:"title"` + Content string `json:"content"` +} + +func (k *Knowledge) IndexName() string { + return "catface_knowledges" +} + +func (k *Knowledge) InsertDocument() error { + ctx := context.Background() + + k.Id = int32(time.Now().UnixNano() / 1e6) // 将纳秒级时间戳转换为毫秒级 // INFO 自动补充时间戳为 ID + + // 将结构体转换为 JSON 字符串 + data, err := json.Marshal(k) + if err != nil { + return err + } + + // 创建请求 + req := esapi.IndexRequest{ + Index: k.IndexName(), + // DocumentID: fmt.Sprintf("%d", k.Id), + Body: bytes.NewReader(data), + Refresh: "true", + } + + // 发送请求 + res, err := req.Do(ctx, variable.ElasticClient) + if err != nil { + return err + } + defer res.Body.Close() + + if res.IsError() { + var k map[string]interface{} + if err := json.NewDecoder(res.Body).Decode(&k); err != nil { + return fmt.Errorf("error parsing the response body: %s", err) + } else { + return fmt.Errorf("[%s] %s: %s", + res.Status(), + k["error"].(map[string]interface{})["type"], + k["error"].(map[string]interface{})["reason"], + ) + } + } + + return nil +} + +// RandomDocuments 随机查询 num 个文档 +func (k *Knowledge) RandomDocuments(num int) ([]*Knowledge, error) { + ctx := context.Background() + + // 创建本地随机数生成器 // TIP rand.Seed() 在 Go1.20 之后弃用了。 + rng := rand.New(rand.NewSource(time.Now().UnixNano())) + + // 创建请求 + req := esapi.SearchRequest{ + Index: []string{k.IndexName()}, + Body: strings.NewReader(fmt.Sprintf(`{ + "size": %d, + "query": { + "function_score": { + "query": { "match_all": {} }, + "random_score": { + "seed": %d + } + } + } + }`, num, rng.Int63())), + } + + // 发送请求 + res, err := req.Do(ctx, variable.ElasticClient) + if err != nil { + return nil, err + } + defer res.Body.Close() + + if res.IsError() { + var k map[string]interface{} + if err := json.NewDecoder(res.Body).Decode(&k); err != nil { + return nil, fmt.Errorf("error parsing the response body: %s", err) + } else { + return nil, fmt.Errorf("[%s] %s: %s", + res.Status(), + k["error"].(map[string]interface{})["type"], + k["error"].(map[string]interface{})["reason"], + ) + } + } + + // 解析响应 + var result map[string]interface{} + if err := json.NewDecoder(res.Body).Decode(&result); err != nil { + return nil, err + } + + // 提取文档 + hits := result["hits"].(map[string]interface{})["hits"].([]interface{}) + + documents := make([]*Knowledge, len(hits)) + for i, hit := range hits { + source := hit.(map[string]interface{})["_source"].(map[string]interface{}) + + // 将 []interface{} 转换为 []string + dirs := make([]string, len(source["dirs"].([]interface{}))) + for j, dir := range source["dirs"].([]interface{}) { + dirs[j] = dir.(string) + } + + doc := &Knowledge{ + Dirs: dirs, + Title: source["title"].(string), + Content: source["content"].(string), + } + documents[i] = doc + } + + return documents, nil +} diff --git a/test/es/encounter_test.go b/test/es/encounter_test.go index 3eaac97..98d41cb 100644 --- a/test/es/encounter_test.go +++ b/test/es/encounter_test.go @@ -1,7 +1,6 @@ package test import ( - "catface/app/global/variable" "catface/app/model" "catface/app/model_es" _ "catface/bootstrap" @@ -35,7 +34,7 @@ func TestEncounterEs(t *testing.T) { // } // 查询文档 - encounters, err := encounter.QueryDocumentsMatchAll(variable.ElasticClient, "猪皮") + encounters, err := encounter.QueryDocumentsMatchAll("猪皮") if err != nil { t.Fatalf("查询文档时出错: %s", err) } diff --git a/test/es/knowledge_test.go b/test/es/knowledge_test.go new file mode 100644 index 0000000..f94138b --- /dev/null +++ b/test/es/knowledge_test.go @@ -0,0 +1,119 @@ +package test + +import ( + "catface/app/model_es" + _ "catface/bootstrap" + "testing" +) + +var Know_vacc_1 = []model_es.Knowledge{ + { + Dirs: []string{"疫苗", "喵三联"}, + Title: "概念", + Content: "喵三联疫苗是一种针对猫咪的疫苗组合,通常包含三种疫苗,以提供对猫瘟、白血、传腹三种主要疾病的防护。", + }, + { + Dirs: []string{"疫苗", "喵三联"}, + Title: "接种周期", + Content: "1. 幼猫:通常在6-8周大开始接种第一剂,之后每3-4周接种一次,直到完成基础免疫。\n2. 成猫:完成基础免疫后,每年进行一次加强接种。", + }, + { + Dirs: []string{"疫苗", "喵三联"}, + Title: "副作用", + Content: "像所有疫苗一样,喵三联疫苗可能会有轻微的副作用,如注射部位的红肿、疼痛或轻微的发烧。", + }, +} + +var Know_food = []model_es.Knowledge{ + { + Dirs: []string{"食物"}, + Title: "猫粮", + Content: "选择专为猫设计的猫粮,考虑其年龄、体重、健康状况和活动水平,确保营养均衡,避免含有对猫有害的成分。", + }, + { + Dirs: []string{"食物"}, + Title: "猫条", + Content: "猫条可作为零食或训练工具,选择高质量猫条,适量喂食,注意热量控制,避免肥胖。", + }, + { + Dirs: []string{"食物"}, + Title: "人类食物对猫的影响", + Content: "人类食物可能不适合猫,某些食物对猫有毒,高盐、高糖或高脂肪食物可能导致健康问题,不应作为猫咪日常饮食。", + }, + { + Dirs: []string{"食物"}, + Title: "猫粮的营养成分", + Content: "猫粮应包含高质量的蛋白质、脂肪、维生素和矿物质,以满足猫的营养需求。", + }, +} + +var Know_WHU = []model_es.Knowledge{ + { + Dirs: []string{"WHU"}, + Title: "狂犬疫苗接种点", + Content: "地质医院是离武大最近的接种点。", + }, +} + +var Know_viuse = []model_es.Knowledge{ + { + Dirs: []string{"狂犬病"}, + Title: "概念", + Content: "狂犬病毒是一种通过动物咬伤或唾液传播的病毒,主要影响中枢神经系统,对人类和动物都具有致命性。", + }, + { + Dirs: []string{"狂犬病"}, + Title: "人类症状", + Content: "人类感染狂犬病毒后,初期可能表现为发热、头痛、恶心等症状,随后可能出现恐惧、兴奋、幻觉、瘫痪和昏迷等严重症状。", + }, + { + Dirs: []string{"狂犬病"}, + Title: "传播途径", + Content: "狂犬病毒主要通过被感染动物的咬伤传播,也可能通过唾液直接接触眼睛、鼻子或口腔而传播。", + }, + { + Dirs: []string{"狂犬病"}, + Title: "与猫", + Content: "猫可以感染狂犬病毒,但通常不表现出明显症状,可能成为无症状携带者,传播风险相对较低。", + }, + { + Dirs: []string{"狂犬病"}, + Title: "猫狗预防", + Content: "定期给猫接种狂犬病疫苗,避免与野生动物接触,及时处理伤口,并在疑似暴露后采取隔离措施。", + }, + { + Dirs: []string{"狂犬病"}, + Title: "人类预防", + Content: "避免接触可能携带狂犬病毒的动物,被动物咬伤后立即清洗伤口并接种疫苗,了解并遵守当地狂犬病预防和动物管理的法律法规。", + }, + { + Dirs: []string{"狂犬病"}, + Title: "治疗方法", + Content: "狂犬病目前没有特效治疗,治疗主要针对症状,因此预防措施至关重要。", + }, +} + +func TestKnowledgesES(t *testing.T) { + // 定义需要插入的数据 + knowledges := append((append(append(Know_viuse, Know_food...), Know_WHU...)), Know_vacc_1...) + + // 遍历并插入每个知识条目 + for _, knowledge := range knowledges { + err := knowledge.InsertDocument() + if err != nil { + t.Fatalf("Error inserting document: %v", err) + } + } +} + +func TestRandomSearch(t *testing.T) { + knowledges, err := model_es.CreateKnowledgeESFactory().RandomDocuments(5) + if err != nil { + t.Fatalf("Error retrieving random documents: %v", err) + } + + t.Log("随机搜索结果:", len(knowledges)) + for _, knowledge := range knowledges { + t.Log(knowledge) + } +}