Nano Hash - криптовалюты, майнинг, программирование

Как использовать токенизатор ngram и edge ngram вместе в индексе elasticsearch?

У меня есть указатель, содержащий 3 документа.

            {
                    "firstname": "Anne",
                    "lastname": "Borg",
                }

            {
                    "firstname": "Leanne",
                    "lastname": "Ray"
                },

            {
                    "firstname": "Anne",
                    "middlename": "M",
                    "lastname": "Stone"
                }

Когда я ищу «Анна», я хотел бы, чтобы эластичный элемент возвращал все 3 из этих документов (потому что все они в определенной степени соответствуют термину «Анна»). НО, я бы хотел, чтобы у Линн Рэй была более низкая оценка (рейтинг релевантности), потому что поисковый термин «Анна» появляется в этом документе на более поздней позиции, чем термин, указанный в двух других документах.

Изначально я использовал токенизатор ngram. У меня также есть сгенерированное поле в сопоставлении моего индекса под названием «full_name», которое содержит строки имени, отчества и фамилии. Когда я искал "Anne", все 3 документа были в наборе результатов. Тем не менее, Энн М. Стоун набрала столько же очков, что и Линн Рэй. Энн М. Стоун должна иметь более высокий балл, чем Линн.

Чтобы решить эту проблему, я изменил свой токенизатор ngram на токенизатор edge_ngram. Это привело к тому, что Линн Рэй была полностью исключена из набора результатов. Мы хотели бы сохранить этот результат в наборе результатов - потому что он все еще содержит строку запроса - но с более низкой оценкой, чем два других лучших совпадения.

Я где-то читал, что можно использовать фильтр edge ngram вместе с фильтром ngram в том же индексе. Если да, то как мне для этого воссоздать свой индекс? Есть ли лучшее решение?

Вот начальные настройки индекса.

{
    "settings": {
        "analysis": {
            "analyzer": {
                "my_analyzer": {
                    "filter": [
                        "lowercase"
                    ],
                    "type": "custom",
                    "tokenizer": "my_tokenizer"
                }
            },
            "tokenizer": {
                "my_tokenizer": {
                    "token_chars": [
                        "letter",
                        "digit",
                        "custom"
                    ],
                    "custom_token_chars": "'-",
                    "min_gram": "3",
                    "type": "ngram",
                    "max_gram": "4"
                }
            }
        }
    },
    "mappings": {
        "properties": {
            "contact_id": {
                "type": "text",
                "fields": {
                    "keyword": {
                        "type": "keyword",
                        "ignore_above": 256
                    }
                }
            },

            "firstname": {
                "type": "text",
                "fields": {
                    "keyword": {
                        "type": "keyword"
                    }
                },
                "copy_to": [
                    "full_name"
                ]
            },


            "lastname": {
                "type": "text",
                "fields": {
                    "keyword": {
                        "type": "keyword"
                    }
                },
                "copy_to": [
                    "full_name"
                ]
            },

            "middlename": {
                "type": "text",
                "fields": {
                    "keyword": {
                        "type": "keyword",
                        "ignore_above": 256
                    }
                },
                "copy_to": [
                    "full_name"
                ]
            },

            "full_name": {
                "type": "text",
                "analyzer": "my_analyzer",
                "fields": {
                    "keyword": {
                        "type": "keyword"
                    }
                }
            }
        }
    }
}

И вот мой запрос

{
    "query": {
        "bool": {
            "should": [
                {
                    "query_string": {
                        "query": "Anne",
                        "fields": [
                            "full_name"
                        ]
                    }
                }
            ]
        }
    }
}

Это вернуло эти результаты

    "hits": {
        "total": {
            "value": 3,
            "relation": "eq"
        },
        "max_score": 0.59604377,
        "hits": [
            {
                "_index": "contacts_15",
                "_type": "_doc",
                "_id": "3",
                "_score": 0.59604377,
                "_source": {
                    "firstname": "Anne",
                    "lastname": "Borg"
                }
            },
            {
                "_index": "contacts_15",
                "_type": "_doc",
                "_id": "1",
                "_score": 0.5592099,
                "_source": {
                    "firstname": "Anne",
                    "middlename": "M",
                    "lastname": "Stone"
                }
            },
            {
                "_index": "contacts_15",
                "_type": "_doc",
                "_id": "2",
                "_score": 0.5592099,
                "_source": {
                    "firstname": "Leanne",
                    "lastname": "Ray"
                }
            }
        ]
    }

Если вместо этого я использую токенизатор edge ngram, настройки индекса будут выглядеть так ...

{
    "settings": {
        "max_ngram_diff": "10",
        "analysis": {
            "analyzer": {
                "my_analyzer": {
                    "filter": [
                        "lowercase"
                    ],
                    "type": "custom",
                    "tokenizer": ["edge_ngram_tokenizer"]
                }
            },
            "tokenizer": {
                "edge_ngram_tokenizer": {
                    "token_chars": [
                        "letter",
                        "digit",
                        "custom"
                    ],
                    "custom_token_chars": "'-",
                    "min_gram": "2",
                    "type": "edge_ngram",
                    "max_gram": "10"
                }
            }
        }
    },
    "mappings": {
        "properties": {
            "contact_id": {
                "type": "text",
                "fields": {
                    "keyword": {
                        "type": "keyword",
                        "ignore_above": 256
                    }
                }
            },

            "firstname": {
                "type": "text",
                "fields": {
                    "keyword": {
                        "type": "keyword"
                    }
                },
                "copy_to": [
                    "full_name"
                ]
            },


            "lastname": {
                "type": "text",
                "fields": {
                    "keyword": {
                        "type": "keyword"
                    }
                },
                "copy_to": [
                    "full_name"
                ]
            },

            "middlename": {
                "type": "text",
                "fields": {
                    "keyword": {
                        "type": "keyword",
                        "ignore_above": 256
                    }
                },
                "copy_to": [
                    "full_name"
                ]
            },

            "full_name": {
                "type": "text",
                "analyzer": "my_analyzer",
                "fields": {
                    "keyword": {
                        "type": "keyword"
                    }
                }
            }
        }
    }
}

и тот же запрос возвращает этот новый набор результатов ...

   "hits": {
        "total": {
            "value": 2,
            "relation": "eq"
        },
        "max_score": 1.5131824,
        "hits": [
            {
                "_index": "contacts_16",
                "_type": "_doc",
                "_id": "3",
                "_score": 1.5131824,
                "_source": {
                    "firstname": "Anne",
                    "middlename": "M",
                    "lastname": "Stone"
                }
            },
            {
                "_index": "contacts_16",
                "_type": "_doc",
                "_id": "1",
                "_score": 1.4100108,
                "_source": {
                    "firstname": "Anne",
                    "lastname": "Borg"
                }
            }
        ]
    }
12.05.2020

Ответы:


1

Вы можете продолжать использовать ngram (то есть первое решение), но тогда вам нужно изменить свой запрос, чтобы повысить релевантность. Это работает следующим образом: вы добавляете усиленный запрос multi_match в предложение should, чтобы увеличить оценку документов, имя или фамилия которых точно совпадают с введенными данными:

{
  "query": {
    "bool": {
      "must": [
        {
          "query_string": {
            "query": "Anne",
            "fields": [
              "full_name"
            ]
          }
        }
      ],
      "should": [
        {
          "multi_match": {
            "query": "Anne",
            "fields": [
              "firstname",
              "lastname"
            ],
            "boost": 10
          }
        }
      ]
    }
  }
}

Этот запрос принесет Anne Borg и Anne M Stone перед Leanne Ray.

ОБНОВЛЕНИЕ

Вот как я пришел к результатам.

Сначала я создал тестовый индекс с теми же настройками / сопоставлениями, которые вы добавили в свой вопрос:

PUT test
{ ... copy/pasted mappings/settings ... }

Затем я добавил три предоставленных вами образца документов:

POST test/_doc/_bulk
{"index":{}}
{"firstname":"Anne","lastname":"Borg"}
{"index":{}}
{"firstname":"Leanne","lastname":"Ray"}
{"index":{}}
{"firstname":"Anne","middlename":"M","lastname":"Stone"}

Наконец, если вы запустите мой запрос выше, вы получите следующие результаты, которые как раз и ожидаете (посмотрите на результаты):

{
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 5.1328206,
    "hits" : [
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "4ZqbDHIBhYuDqANwQ-ih",
        "_score" : 5.1328206,
        "_source" : {
          "firstname" : "Anne",
          "lastname" : "Borg"
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "45qbDHIBhYuDqANwQ-ih",
        "_score" : 5.0862665,
        "_source" : {
          "firstname" : "Anne",
          "middlename" : "M",
          "lastname" : "Stone"
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "4pqbDHIBhYuDqANwQ-ih",
        "_score" : 0.38623023,
        "_source" : {
          "firstname" : "Leanne",
          "lastname" : "Ray"
        }
      }
    ]
  }
}
12.05.2020
  • Этот запрос вообще не возвращает Линн Рэй. 12.05.2020
  • Вам следует попробовать еще раз с нуля, потому что все, что я сообщил выше, было основано на реальных тестах с вашим отображением и образцами данных, которые вы предоставили, а не на предположениях ;-) Или обновите свой вопрос, указав, что вы пытаетесь сделать, и мы увидим, где это чешется 12.05.2020
  • Спасибо, Вэл. Я сделал свой вопрос немного проще. Это полезно? Какой еще информацией было бы полезно поделиться? Я не могу думать ни о чем другом. 13.05.2020
  • Я обновил свой ответ, чтобы показать вам, как я создал свой запрос и какие результаты он возвращает. Я не менял запрос, так как он работает так, как вы ожидаете. 13.05.2020
  • Спасибо. Виноват. Ваш запрос действительно отвечает на мой вопрос. Есть еще одна проблема, которую я задаю в новом вопросе, потому что ваш ответ на этот вопрос исчерпан. Возможно, вы сможете пролить свет на эту, возможно, более типичную ситуацию stackoverflow.com/questions/61768534/ 13.05.2020
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..