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
相关推荐
南宫理的日知录30 分钟前
99、Python并发编程:多线程的问题、临界资源以及同步机制
开发语言·python·学习·编程学习
coberup39 分钟前
django Forbidden (403)错误解决方法
python·django·403错误
筱源源1 小时前
Elasticsearch-linux环境部署
linux·elasticsearch
龙哥说跨境1 小时前
如何利用指纹浏览器爬虫绕过Cloudflare的防护?
服务器·网络·python·网络爬虫
小白学大数据1 小时前
正则表达式在Kotlin中的应用:提取图片链接
开发语言·python·selenium·正则表达式·kotlin
flashman9111 小时前
python在word中插入图片
python·microsoft·自动化·word
菜鸟的人工智能之路2 小时前
桑基图在医学数据分析中的更复杂应用示例
python·数据分析·健康医疗
懒大王爱吃狼3 小时前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
秃头佛爷4 小时前
Python学习大纲总结及注意事项
开发语言·python·学习
深度学习lover5 小时前
<项目代码>YOLOv8 苹果腐烂识别<目标检测>
人工智能·python·yolo·目标检测·计算机视觉·苹果腐烂识别