Почему мой запрос с использованием анализатора MinHa sh не может получить дубликаты? - PullRequest
0 голосов
/ 03 августа 2020

Я пытаюсь запросить индекс Elasticsearch на наличие почти дубликатов, используя его MinHa sh реализацию . Я использую клиент 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, пытаюсь использовать пользовательские настройки и анализатор, вдохновляясь официальными примерами и MinHa sh docs :

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 Я получаю то, что кажется в порядке:

enter image description here

However, querying the index with:

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'] постоянно пуст, даже если я установил свой body для соответствия точно тексту одной из записей в моем корпусе. Другими словами, я не получу никаких результатов, если попробую использовать значения для body, например,

"I come up here for perception and clarity"

или подстроки, такие как

"I come up here for perception"

, в то время как в идеале мне нужна процедура для возврата почти дубликатов, при этом оценка является приближением схожести запроса по Жаккару и почти дубликатов, полученных через MinHa sh.

Что-то не так в моем запросе и / или в том, как я index Elasticsearch? Не хватает ли мне чего-то еще?

PS: вы можете посмотреть https://github.com/davidefiocco/dockerized-elasticsearch-duplicate-finder/tree/ea0974363b945bf5f85d52a781463fba76f4f987 нефункциональный, но, надеюсь, воспроизводимый пример (я также буду обновлять репо, когда найду решение!)

1 Ответ

1 голос
/ 03 августа 2020

Вот некоторые вещи, которые вам следует перепроверить, поскольку они, вероятно, являются виновниками:

  • при создании сопоставления вы должны изменить с «name» на «text» в 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 в ha sh. Таким образом, вы можете запрашивать это поле с помощью ha sh, а не с помощью строки, как в вашем примере "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']]
    
...