natasha / yargy

Rule-based facts extraction for Russian language
MIT License
315 stars 40 forks source link

Repeatable с ограниченным числом повторений, самый левый match, теггер отдельно от токенизатора #50

Closed kuk closed 6 years ago

kuk commented 6 years ago
  1. В .repeatable можно указывать аргументы min, max

Не практике редко нужно повторение бесконечное число раз. Также .repeatable может приводить к "взрывам" по памяти и времени выполнения. Также пользователи уже несколько раз просили возможность ограничить число повторений .repeable

Раньше такую функциональность можно было получить вручную:

or_(
  ITEM,
  rule(ITEM, ITEM),
  rule(ITEM, ITEM, ITEM),
  ...
)

rule(
  ITEM,
  ITEM.optional(),
  ITEM.optional(),
  ...
)

Сейчас можно написать .repeatable(max=3). Какой-то низкоуровневой поддрежки в парсере нет. Выражение просто разворачивается в

or_(
  ITEM,
  rule(
    ITEM,
    or_(
      ITEM,
      rule(
         ITEM, ITEM
      )
    )
  )
)
  1. Самый левый метч

Иногда грамматика бывает неоднозначной. Когда пользователь вызывает .match возвращается, на самом деле, какой-то один случайный разбор. Когда пользователь вызывает .findall возвращается самый длинный метч, но когда метчи одного размера из них опять выбирается один случайный. Например есть грамматика

ITEM = or_(
  rule('a', 'b'),
  rule('a'),
  rule('b')
)
ITEMS = ITEM.repeatable()

Строчка a b a b может иметь разборы (a b) (a b), (a) (b) (a b), (a b) (a) (b), (a) (b) (a) (b). Раньше нельзя было гарантировать какой вернётся первым. Сейчас возвращается самый левый разор (a b) (a b)

Если бы было

ITEM = or_(
  rule('a'),
  rule('b')
  rule('a', 'b') 
)

вернулся бы (a) (b) (a) (b)

То есть теперь порядок аргументов в or_ влияет на результат.

  1. Аргумент tagger в Parser

Раньше CRF-теггер предлагалось использовать через токенизатор. Делать TagMorphTokenizer(CrfTagger(...)). Это не очень удобно и неочевидно. Теперь предлагается задавать теггер отдельным аргументом Parser(RULE, tagger=CrfTagger(...))

  1. Более оптимальная реализация match. Парсер не пытается начать применять правило с каждого токена, применяет только к первому