ValueError: nlp.add_pipe now takes the string name of the registered component factory, not a callable component

Viewed 10059

The following link shows how to add custom entity rule where the entities span more than one token. The code to do that is below:

import spacy
from spacy.pipeline import EntityRuler
nlp = spacy.load('en_core_web_sm', parse=True, tag=True, entity=True)

animal = ["cat", "dog", "artic fox"]
ruler = EntityRuler(nlp)
for a in animal:
    ruler.add_patterns([{"label": "animal", "pattern": a}])
nlp.add_pipe(ruler)


doc = nlp("There is no cat in the house and no artic fox in the basement")

with doc.retokenize() as retokenizer:
    for ent in doc.ents:
        retokenizer.merge(doc[ent.start:ent.end])


from spacy.matcher import Matcher
matcher = Matcher(nlp.vocab)
pattern =[{'lower': 'no'},{'ENT_TYPE': {'REGEX': 'animal', 'OP': '+'}}]
matcher.add('negated animal', None, pattern)
matches = matcher(doc)


for match_id, start, end in matches:
    span = doc[start:end]
    print(span)

I tried but i got the error bellow:

  • If you created your component with nlp.create_pipe('name'): remove nlp.create_pipe and call nlp.add_pipe('name') instead.

  • If you passed in a component like TextCategorizer(): call nlp.add_pipe with the string name instead, e.g. nlp.add_pipe('textcat').

  • If you're using a custom component: Add the decorator @Language.component (for function components) or @Language.factory (for class components / factories) to your custom component and assign it a name, e.g. @Language.component('your_name'). You can then run nlp.add_pipe('your_name') to add it to the pipeline.

How can I fixed please? NB: spaCy version 3.0.6

3 Answers

For spaCy v2, the normal way to add an entity ruler looked like this:

ruler = EntityRuler(nlp)
nlp.add_pipe(ruler)
ruler.add_patterns(...)

For spaCy v3, you just want to add it with its string name and skip instantiating the class separately:

ruler = nlp.add_pipe("entity_ruler")
ruler.add_patterns(...)

See: https://spacy.io/usage/v3#migrating-add-pipe

You need to define your own method to instantiate the entity ruler:

def get_ent_ruler(nlp, name):
    ruler = EntityRuler(nlp)
    for a in animal:
        ruler.add_patterns([{"label": "animal", "pattern": a}])
    return ruler

Then, you may use it the following way:

from spacy.language import Language
Language.factory("ent_ruler", func=get_ent_ruler)
nlp.add_pipe("ent_ruler", last=True)

Also, note the pattern you wrote is not valid. I think you can fix it like this:

pattern =[{'lower': 'no'},{'ENT_TYPE': 'animal'}]

Then, the result is

no cat
no artic fox

For spacy 3.0+, your code should be changed as the following:

import spacy
import re
from spacy.language import Language

nlp = spacy.load('en_core_web_sm')
boundary = re.compile('^[0-9]$')

@Language.component("component")
def custom_seg(doc):
    prev = doc[0].text
    length = len(doc)
    for index, token in enumerate(doc):
        if (token.text == '.' and boundary.match(prev) and index!=(length - 1)):
            doc[index+1].sent_start = False
        prev = token.text
    return doc
    
nlp.add_pipe("component", before='parser')
Related