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
相关推荐
梧桐树042922 分钟前
python常用内建模块:collections
python
Dream_Snowar30 分钟前
速通Python 第三节
开发语言·python
woshiabc1112 小时前
windows安装Elasticsearch及增删改查操作
大数据·elasticsearch·搜索引擎
蓝天星空2 小时前
Python调用open ai接口
人工智能·python
jasmine s2 小时前
Pandas
开发语言·python
郭wes代码2 小时前
Cmd命令大全(万字详细版)
python·算法·小程序
leaf_leaves_leaf2 小时前
win11用一条命令给anaconda环境安装GPU版本pytorch,并检查是否为GPU版本
人工智能·pytorch·python
夜雨飘零12 小时前
基于Pytorch实现的说话人日志(说话人分离)
人工智能·pytorch·python·声纹识别·说话人分离·说话人日志
404NooFound2 小时前
Python轻量级NoSQL数据库TinyDB
开发语言·python·nosql
天天要nx3 小时前
D102【python 接口自动化学习】- pytest进阶之fixture用法
python·pytest