python使用elasticserch进行混合搜索构建知识库

python使用elasticserch进行混合搜索

基于python使用elasticserch

安装elasticsearch

pip install elasticsearch

连接elasticsearch

es_username = "elastic"
es_password = "123456"
es = Elasticsearch(
    ['https://0.0.0.0:9200'],
    basic_auth=(es_username, es_password),verify_certs=False
    )

创建索引

python 复制代码
#settings: 定义了索引的设置,包括了主分片数量和副本数量。一个主分片和0副本。
#id类型为 keyword,意味着它是一个精确值字段,不会被分词。
#title 和 content: 表示标题和内容的字段,类型为 text,使用了中文分词器(ik_smart 和 ik_max_word)进行分析,并且都被配置为存储。
#title_vec 和 vectors.features: 表示向量字段的字段,类型为 dense_vector,意味着它们存储了稠密向量。这些向量字段还指定了维度(dims),相似度度量方式(similarity,这里是余弦相似度),以及是否被索引(index,设置为 True)。
#vectors.segment: 表示文档中的某一段落的字段,类型为 text,使用了中文分词器,并且被配置为存储。
index_name = "zft_lnn"
index_settings = {
    'settings': {
        'number_of_shards': 1,
        'number_of_replicas': 0
    },
    'mappings': {
        "properties": {
            "id": {
                "store": True,
                "type": "keyword"
            },  
            "title": {
                "search_analyzer": "ik_smart",
                "analyzer": "ik_max_word",
                "store": True,
                "type": "text"
            },
            "content": {
                "search_analyzer": "ik_smart",
                "analyzer": "ik_max_word",
                "store": True,
                "type": "text"
            },
            "title_vec": {
                "dims": 768,
                "similarity": "cosine",
                "index": True,
                "type": "dense_vector"
            },
            "vectors": {
                "type": "nested",
                "properties": {
                    "features": {
                        "dims": 768,
                        "similarity": "cosine",
                        "index": True,
                        "type": "dense_vector"
                    },
                    "segment": {"search_analyzer": "ik_smart",
                                "analyzer": "ik_max_word",
                                "store": True,
                                "type": "text"}
                }
            }
        }
    }
}
python 复制代码
es.indices.create(index=index_name, body=index_settings)

写入数据

待写入数据存储在json文件中,里面是query和answer的对子。

import json

# 读取JSON文件
with open('answer.json', 'r', encoding='utf-8') as file:
    data = json.load(file)
    
count = 1
for item in data:
    title = item["query"]
    content  = item["answer"]
    index_name = "zft_bge"
    title_vec = vector_model.encode(title)
    content_vec = vector_model.encode(content)
    id = str(count)
    count += 1

    datas = {}
    datas["id"] = id
    datas["title"] = title
    datas["content"] = content
    datas["title_vec"] = title_vec
    datas["content_vec"] = content_vec

    document = {
        "id": datas["id"],
        "title": datas["title"],
        "title_vec":datas["title_vec"],
        "content":datas["content"],
        "content_vec":datas["content_vec"]
    }
    response = es.index(index=index_name,id=datas["id"], body=document)

搜索数据

关键字搜索

IK 分词器可以将中文文本切分成一个个有意义的词语,并计算这些词语的词频(term frequency,TF),用于构建倒排索引。在搜索时,Elasticsearch 会根据查询词的词频和文档中各个词语的词频来计算文档的相关性得分,从而排序返回搜索结果。

python 复制代码
boostqu = {
          "match": {
            "title": {
              "query": qa,
              "boost": 1.5
            }
          }
        }
query = {
        "query": {
            "function_score": {
                "query": {
                    "bool": {
                        "should": boostqu
                    }
                },
                "functions": [
                    {
                        "script_score": {
                            "script": {
                                "source": "Math.sqrt(_score)/2",
                                "lang": "painless",
                            }
                        }
                    }
                ],
                "boost_mode": "replace"
            }
        },
}

results = es.search(index=index_name, body=query)
hits = results["hits"]["hits"]
for h in hits:
    print(h["_source"]["title"],h['_score'])

KNN搜索

在 Elasticsearch 中,KNN 搜索通常用于基于向量的相似性搜索,例如基于词嵌入向量或其他类型的向量来查找最相似的文档或项。

python 复制代码
query_vector = vector_model.encode(qa)
query = {
  "query": {
    "bool": {
      "should": [
        {
          "knn": {
            "field": "title_vec",
            "query_vector": query_vector,
            "num_candidates": 10,
            "boost": 1.0
          }
        }
      ]
    }
  }
}
results = es.search(index=index_name, body=query)
hits = results["hits"]["hits"]
for h in hits:
    print(h["_source"]["title"],h['_score'])

向量搜索

python 复制代码
query_vector = vector_model.encode(qa)
query = {
  "query": {
    # 通过 script score 来自定义查询的分值计算
    "script_score": {
      "query": {
        # 此处可以结合其他约束条件
        "match_all": {}
      },
      # 稠密向量查询的重点在此处,通过 script 的方式指定具体的计算方式
      # 此处是计算余弦相似度,也可以替换其他的相似度
      "script": {
		# 余弦相似度计算需要两个参数:本次待查询的向量 queryVector 和索引中的字段 entity_name_embedding
        "source": "cosineSimilarity(params.queryVector, 'title_vec')",
        "lang": "painless",
		# 此处将本次待查询的向量传入,注意"params"中 queryVector 和 "source"中的书写要保持一致。
        "params": {
          # 768 维的待查询向量
          "queryVector": query_vector
        }
      },
       "boost": 1.0,
    }
  },
}
results = es.search(index=index_name, body=query)
hits = results["hits"]["hits"]
for h in hits:
    print(h["_source"]["title"],h['_score'])

混合搜索

在混合搜索中,可以在不同方式的搜索加入权重,进行去权重的相加,从而得到一个更好的结果,这个权重参数更多的需要结合实际场景进行设置。

python 复制代码
#混合搜索
def multiserch(es,vector_model,qa):
    query_vector = vector_model.encode(qa)

    key_boostqu = [{"match": {"title": {"query": qa, "boost": 1.2}}},
               {"match": {"content": {"query": qa, "boost": 0.8}}},]

    query = {
    "query": {
        "bool": {
        "should": [
            {
            "function_score": {
                "query": {
                        "bool": {
                            "should": key_boostqu
                        }
                    },
                "functions": [
                {
                    "script_score": {
                    "script": {
                        "source": "Math.sqrt(_score)/2",
                        "lang": "painless"
                    }
                    }
                }
                ],
                "boost_mode": "replace"
            }
            },
        
            {
            "script_score": {
                "query": {
                "match_all": {}
                },
                "script": {
                "source": "cosineSimilarity(params.queryVector, 'title_vec')",
                "lang": "painless",
                "params": {
                    "queryVector": query_vector
                }
                },
                "boost": 1.0
            }
            }
        ]
        }
    },
        "knn": {
        "field": "title_vec",
        "query_vector": query_vector,
        "k": 1,
        "num_candidates": 10,
        "boost": 0.5
        },
        "knn": {
        "field": "content_vec",
        "query_vector": query_vector,
        "k": 1,
        "num_candidates": 10,
        "boost": 0.5
        },
    "size": 3
    }

    results = es.search(index=index_name, body=query)
    hits = results["hits"]["hits"]
    for h in hits:
        print(h["_source"]["title"],h['_score'])
        print(h["_source"]["content"])
    content = hits[0]["_source"]["content"]
    return content
相关推荐
VisionX Lab几秒前
数据脱敏工具:基于 FFmpeg 的视频批量裁剪
python·ffmpeg·音视频
枫哥和java3 小时前
python serializer, model drf通过序列化器, 模型获取mysql 一张表某个字段数据库现存的最大值
数据库·python·mysql
无忧无虑Coding5 小时前
pyinstall 打包Django程序
后端·python·django
ad禥思妙想7 小时前
如何运行python脚本
开发语言·python
威威猫的栗子7 小时前
用 Python 与 Turtle 创作属于你的“冰墩墩”!
开发语言·python·turtle
IT古董7 小时前
【机器学习】超简明Python基础教程
开发语言·人工智能·python·机器学习
qq_q9922502778 小时前
django基于python 语言的酒店推荐系统
后端·python·django
小李L8 小时前
Python3 Flask 应用中使用阿里短信发送
后端·python·flask
好看资源平台8 小时前
动态网站数据爬取——Selenium的使用
爬虫·python
威威猫的栗子8 小时前
Python Turtle绘图:重现汤姆劈树的经典瞬间
开发语言·python