Elastic Search Analyzer для динамически определенных поисков регулярных выражений - PullRequest
1 голос
/ 15 октября 2019

У нас много документов в эластичном поисковом индексе, и в настоящий момент мы выполняем полнотекстовый поиск. Следующее мое требование в проекте - найти все данные кредитных карт в документах. Также в будущем пользователь сможет динамически определять некоторые правила поиска по регулярным выражениям. Но со стандартным анализатором невозможно найти информацию о кредитной карте или любое другое пользовательское правило. Например, допустим, что документ содержит информацию о кредитной карте, такую ​​как 4321-4321-4321-4321 или 4321 4321 4321 4321. Эластичный поиск индексирует эти данные как 4 части, как показано ниже:

  "tokens" : [
    {
      "token" : "4321",
      "start_offset" : 0,
      "end_offset" : 4,
      "type" : "<NUM>",
      "position" : 0
    },
    {
      "token" : "4321",
      "start_offset" : 5,
      "end_offset" : 9,
      "type" : "<NUM>",
      "position" : 1
    },
    {
      "token" : "4321",
      "start_offset" : 10,
      "end_offset" : 14,
      "type" : "<NUM>",
      "position" : 2
    },
    {
      "token" : "4321",
      "start_offset" : 15,
      "end_offset" : 19,
      "type" : "<NUM>",
      "position" : 3
    }
  ]


Я просто надеваюне принимать во внимание алгоритм Luhm сейчас. Если я выполняю основной поиск по регулярному выражению для поиска кредитной карты с reg exp "([0-9] {4} [-]) {3} [0-9] {4}", он ничего не возвращает, потому что данные не анализируютсяи проиндексированы для этого. Я подумал, что для этой цели мне нужно определить собственный анализатор для поиска по регулярному выражению и сохранить другую версию данных в другом поле или индексе. Но, как я уже говорил, в будущем пользователь будет определять свои собственные шаблоны правил поиска. Как мне определить пользовательский анализатор? Должен ли я определить Ngram Tokenizer (мин: 2, макс: 20) для этого? С помощью ngram tokenizer я думаю, что могу искать все определенные правила регулярных выражений. Но разумно ли это? Проект должен работать с огромными данными без проблем с производительностью. (Вся файловая система компании будет проиндексирована). Есть ли у вас какие-либо другие предложения для этого типа проблемы обнаружения данных? Моя основная цель - найти кредитные карты на данный момент. Спасибо за помощь.

1 Ответ

1 голос
/ 16 октября 2019

Хорошо, вот пара пользовательских анализаторов, которые могут помочь вам определить номера кредитных карт и номера социального страхования. Не стесняйтесь адаптировать регулярное выражение по своему усмотрению (добавив / удалив другие символьные разделители, которые вы найдете в ваших данных).

PUT test
{
  "settings": {
    "analysis": {
      "analyzer": {
        "card_analyzer": {
          "type": "custom",
          "tokenizer": "keyword",
          "filter": [
            "lowercase",
            "card_number"
          ]
        },
        "ssn_analyzer": {
          "type": "custom",
          "tokenizer": "keyword",
          "filter": [
            "lowercase",
            "social_number"
          ]
        }
      },
      "filter": {
        "card_number": {
          "type": "pattern_replace",
          "preserve_original": false,
          "pattern": """.*(\d{4})[\s\.\-]+(\d{4})[\s\.\-]+(\d{4})[\s\.\-]+(\d{4}).*""",
          "replacement": "$1$2$3$4"
        },
        "social_number": {
          "type": "pattern_replace",
          "preserve_original": false,
          "pattern": """.*(\d{3})[\s\.\-]+(\d{2})[\s\.\-]+(\d{4}).*""",
          "replacement": "$1$2$3"
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "text": {
        "type": "text",
        "fields": {
          "card": {
            "type": "text",
            "analyzer": "card_analyzer"
          },
          "ssn": {
            "type": "text",
            "analyzer": "ssn_analyzer"
          }
        }
      }
    }
  }
}

Давайте проверим это.

POST test/_analyze
{
  "analyzer": "card_analyzer",
  "text": "Mr XYZ whose SSN is 442-23-1452 has a credit card whose number was 3526 4728 4723 6374"
}

Будет выдан хороший номер кредитной карты, состоящий только из цифр:

{
  "tokens" : [
    {
      "token" : "3526472847236374",
      "start_offset" : 0,
      "end_offset" : 86,
      "type" : "word",
      "position" : 0
    }
  ]
}

Аналогично для SSN:

POST test/_analyze
{
  "analyzer": "ssn_analyzer",
  "text": "Mr XYZ whose SSN is 442-23-1452 has a credit card whose number was 3526 4728 4723 6374"
}

Будет создан хороший социальный номер только для цифр. защитный номер:

{
  "tokens" : [
    {
      "token" : "442231452",
      "start_offset" : 0,
      "end_offset" : 86,
      "type" : "word",
      "position" : 0
    }
  ]
}

И теперь мы можем искать либо кредитную карту, либо SSN. Допустим, у нас есть следующие два документа. Номера SSN и кредитной карты совпадают, но в них используются разные разделители символов

POST test/_doc
{ "text": "Mr XYZ whose SSN is 442-23-1452 has a credit card whose number was 3526 4728 4723 6374" }

POST test/_doc
{ "text": "SSN is 442.23.1452 belongs to Mr. XYZ. He paid $20 via credit card number 3526-4728-4723-6374" }

Теперь оба документа можно найти, выполнив поиск номера кредитной карты и / или SSN в любом формате:

POST test/_search 
{
  "query": {
    "match": {
      "text.card": "3526 4728 4723 6374"
    }
  }
}

POST test/_search 
{
  "query": {
    "match": {
      "text.card": "3526 4728 4723-6374"
    }
  }
}

POST test/_search 
{
  "query": {
    "match": {
      "text.ssn": "442 23-1452"
    }
  }
}

Все приведенные выше запросы будут совпадать и возвращать оба документа.

...