python - 为什么我使用 MinHash 分析器的查询无法检索到重复项?
问题描述
我正在尝试使用其MinHash implementation查询 Elasticsearch 索引以查找近似重复项。我使用在容器中运行的 Python 客户端来索引和执行搜索。
我的语料库是一个 JSONL 文件,有点像这样:
{"id":1, "text":"I'd just like to interject for a moment"}
{"id":2, "text":"I come up here for perception and clarity"}
...
我成功地创建了一个 Elasticsearch 索引,尝试使用自定义设置和分析器,从官方示例和MinHash 文档中获得灵感:
def create_index(client):
client.indices.create(
index="documents",
body={
"settings": {
"analysis": {
"filter": {
"my_shingle_filter": {
"type": "shingle",
"min_shingle_size": 5,
"max_shingle_size": 5,
"output_unigrams": False
},
"my_minhash_filter": {
"type": "min_hash",
"hash_count": 10,
"bucket_count": 512,
"hash_set_size": 1,
"with_rotation": True
}
},
"analyzer": {
"my_analyzer": {
"tokenizer": "standard",
"filter": [
"my_shingle_filter",
"my_minhash_filter"
]
}
}
}
},
"mappings": {
"properties": {
"name": {"type": "text", "analyzer": "my_analyzer"}
}
},
},
ignore=400,
)
我通过 Kibana 验证索引创建没有大问题,并且通过访问http://localhost:9200/documents/_settings我得到了一些看起来井井有条的东西:
但是,使用以下命令查询索引:
def get_duplicate_documents(body, K, es):
doc = {
'_source': ['_id', 'body'],
'size': K,
'query': {
"match": {
"body": {
"query": body,
"analyzer" : "my_analyzer"
}
}
}
}
res = es.search(index='documents', body=doc)
top_matches = [hit['_source']['_id'] for hit in res['hits']['hits']]
res['hits']
即使我将 my 设置为与我的语料库中的一个条目的文本完全body
匹配, my也始终为空。换句话说,如果我尝试作为例如的值,我不会得到任何结果body
"I come up here for perception and clarity"
或子字符串,如
"I come up here for perception"
虽然理想情况下,我希望该过程返回近似重复项,分数是通过 MinHash 获得的查询和近似重复项的 Jaccard 相似性的近似值。
我的查询和/或索引 Elasticsearch 的方式有问题吗?我是否完全错过了其他东西?
PS:您可以查看https://github.com/davidefiocco/dockerized-elasticsearch-duplicate-finder/tree/ea0974363b945bf5f85d52a781463fba76f4f987以获取非功能性但希望可重现的示例(我也会在找到一个解决方案!)
解决方案
以下是您应该仔细检查的一些事情,因为它们可能是罪魁祸首:
当您创建映射时,您应该在参数
client.indices.create
内部的方法中将“名称”更改为“文本”body
,因为您的 json 文档有一个名为text
:"mappings": { "properties": { "text": {"type": "text", "analyzer": "my_analyzer"} }
在索引阶段,您还可以按照文档
generate_actions()
修改您的方法,例如:for elem in corpus: yield { "_op_type": "index" "_index": "documents", "_id": elem["id"], "_source": elem["text"] }
顺便说一句,如果您正在索引
pandas
数据帧,您可能需要查看实验性官方图书馆eland。此外,根据您的映射,您正在使用
minhash
令牌过滤器,因此 Lucene 会将您的文本转换text
为哈希字段内的文本。因此,您可以使用哈希而不是字符串查询此字段,就像您在示例中所做的那样"I come up here for perception and clarity"
。所以使用它的最好方法是检索字段的内容,text
然后在 Elasticsearch 中查询检索到的相同值。那么元_id
字段不在元字段内_source
,所以你应该改变你的get_duplicate_documents()
方法:def get_duplicate_documents(body, K, es): doc = { '_source': ['text'], 'size': K, 'query': { "match": { "text": { # I changed this line! "query": body } } } } res = es.search(index='documents', body=doc) # also changed the list comprehension! top_matches = [(hit['_id'], hit['_source']) for hit in res['hits']['hits']]
推荐阅读
- sql - 删除给定日期中的重复行组合
- ios - 将字符串快速转换为日期后未显示日期
- c++ - shared_ptr C++ 可能存在内存泄漏
- javascript - Node.js 与 Express 的关系
- apache-kafka - 当您有多个服务实例监听一个主题时会发生什么?
- php - PHP Laravel 按月和年从数据库中提取数据
- batch-file - MS WINDOWS:声明 Tomcat9 的 setenv.bat 用于 THREDDS 服务器 - 我的语法有什么问题?
- react-native - react-native-fbsdk 无法分享视频
- r - 如何使用 twitteR 包获取用户的所有推文
- php - Symfony 未配置 Nginx 服务器