Remove deprecated match common prefix feature from IBL code

This commit is contained in:
Martin Olveyra 2010-12-23 14:40:22 -02:00
parent 633ebc4c43
commit d9a3df45c6
6 changed files with 7 additions and 175 deletions

View File

@ -19,8 +19,7 @@ Main departures from the original algorithm:
from operator import itemgetter
from .regionextract import build_extraction_tree
from .pageparsing import parse_template, parse_extraction_page
from .pageobjects import TokenDict, AnnotationText
from .similarity import common_prefix
from .pageobjects import TokenDict
class InstanceBasedLearningExtractor(object):
"""Implementation of the instance based learning algorithm to
@ -50,35 +49,6 @@ class InstanceBasedLearningExtractor(object):
in parsed_plus_templates if _annotation_count(p)]
parsed_templates = map(itemgetter(0), parsed_plus_epages)
# calculate common text prefixes for annotations of same field across all templates
extracted_text = {}
extraction_pages = map(itemgetter(1), parsed_plus_epages)
for i, parsed in enumerate(parsed_templates):
for annot in parsed.annotations:
if annot.match_common_prefix:
field = annot.surrounds_attribute
if field is not None:
descriptor = type_descriptor.attribute_map.get(field) if type_descriptor else None
allow_markup = descriptor.allow_markup if descriptor else False
start, end = annot.start_index, annot.end_index
if allow_markup:
text = extraction_pages[i].html_between_tokens(start, end)
else:
text = extraction_pages[i].text_between_tokens(start, end)
extracted_text.setdefault(field, []).append(text)
common_prefixes = {}
for field, data in extracted_text.iteritems():
if len(data) > 1:
cprefix = common_prefix(*data)
if cprefix:
common_prefixes[field] = "".join(cprefix).strip()
# now apply common prefixes to annotations
for i, parsed in enumerate(parsed_templates):
for annot in parsed.annotations:
for field, prefix in common_prefixes.iteritems():
if annot.surrounds_attribute == field and not annot.annotation_text:
annot.annotation_text = AnnotationText(prefix)
# templates with more attributes are considered first
sorted_templates = sorted(parsed_templates, key=_annotation_count, reverse=True)
self.extraction_trees = [build_extraction_tree(t, type_descriptor,

View File

@ -189,23 +189,20 @@ class AnnotationTag(object):
tag_attributes - list of (tag attribute, extracted attribute) tuples
for each item to be extracted from a tag attribute
annotation_text - text prefix and suffix for the attribute to be extracted
match_common_prefix - use this annotation for calculating across-template prefixes
metadata - dict with annotation data not used by IBL extractor
"""
__slots__ = ('surrounds_attribute', 'start_index', 'end_index',
'tag_attributes', 'annotation_text', 'variant_id',
'match_common_prefix', 'metadata')
'metadata')
def __init__(self, start_index, end_index, surrounds_attribute=None,
annotation_text=None, tag_attributes=None, variant_id=None,
match_common_prefix=False):
annotation_text=None, tag_attributes=None, variant_id=None):
self.start_index = start_index
self.end_index = end_index
self.surrounds_attribute = surrounds_attribute
self.annotation_text = annotation_text
self.tag_attributes = tag_attributes or []
self.variant_id = variant_id
self.match_common_prefix = match_common_prefix
self.metadata = {}
def __str__(self):

View File

@ -133,8 +133,6 @@ class TemplatePageParser(InstanceLearningParser):
else:
annotation.tag_attributes.append((extract_attribute, tag_value))
self.annotations.append(annotation)
if jannotation.pop('common_prefix', False):
annotation.match_common_prefix = True
self.extra_required_attrs.extend(jannotation.pop('required', []))
annotation.metadata = jannotation
@ -196,9 +194,6 @@ class TemplatePageParser(InstanceLearningParser):
ignored = self.ignored_regions.pop()
self.ignored_regions.append((ignored[0]-1, ignored[1]))
if jannotation.pop('common_prefix', False):
annotation.match_common_prefix = True
self.extra_required_attrs.extend(jannotation.pop('required', []))
attribute_annotations = jannotation.pop('annotations', {}).items()

View File

@ -156,11 +156,8 @@ class BasicTypeExtractor(object):
"""Create a basic type extractor for the annotation"""
text_region = annotation.annotation_text
if text_region is not None:
if annotation.match_common_prefix:
region_extract = TextPrefixRegionDataExtractor(text_region.start_text).extract
else:
region_extract = TextRegionDataExtractor(text_region.start_text,
text_region.follow_text).extract
region_extract = TextRegionDataExtractor(text_region.start_text,
text_region.follow_text).extract
# copy attribute_descriptors and add the text extractor
descriptor_copy = dict(attribute_descriptors)
attr_descr = descriptor_copy.get(annotation.surrounds_attribute,
@ -627,25 +624,4 @@ class TextRegionDataExtractor(object):
return None
return text[pref_index:pref_index + sidx]
class TextPrefixRegionDataExtractor(object):
"""
Data extractor for extracting text fragment from within a
larger body of text, based on a fixed prefix.
>>> extractor = TextPrefixRegionDataExtractor("&pounds;")
>>> extractor.extract("&pounds; 17.00")
' 17.00'
>>> extractor.extract("€ 17.00") is None
True
>>> extractor.extract("$ 17.00") is None
True
>>> extractor.extract(" &pounds; 17.00 ")
' 17.00 '
"""
def __init__(self, prefix):
self.prefix = prefix
def extract(self, text):
text = text.lstrip()
# attempt to extract a substring from the text
if text.startswith(self.prefix):
return text.replace(self.prefix, '')

View File

@ -238,70 +238,6 @@ EXTRACT_PAGE9 = u"""
</body></html>
"""
ANNOTATED_PAGE10a = u"""
<html><body>
<table><tbody>
<tr data-scrapy-annotate="{&quot;variant&quot;: 0, &quot;common_prefix&quot;: true, &quot;annotations&quot;: {&quot;content&quot;: &quot;site_id&quot;}}">
<td>SKU</td><td>L345</td>
</tr>
<tr data-scrapy-annotate="{&quot;variant&quot;: 0, &quot;common_prefix&quot;: true, &quot;annotations&quot;: {&quot;content&quot;: &quot;dimensions&quot;}}">
<td>Size</td><td>10cmx20cm</td>
</tr>
<tr data-scrapy-annotate="{&quot;variant&quot;: 0, &quot;common_prefix&quot;: true, &quot;annotations&quot;: {&quot;content&quot;: &quot;price&quot;}}">
<td>Price</td><td>&pounds;99.00</td>
</tr>
</tbody></table>
</body></html>
"""
ANNOTATED_PAGE10b = u"""
<html><body>
<table><tbody>
<tr data-scrapy-annotate="{&quot;variant&quot;: 0, &quot;common_prefix&quot;: true, &quot;annotations&quot;: {&quot;content&quot;: &quot;site_id&quot;}}">
<td>SKU</td><td>S220</td>
</tr>
<tr data-scrapy-annotate="{&quot;variant&quot;: 0, &quot;common_prefix&quot;: true, &quot;annotations&quot;: {&quot;content&quot;: &quot;dimensions&quot;}}">
<td>Size</td><td>20cmx20cm</td>
</tr>
<tr data-scrapy-annotate="{&quot;variant&quot;: 0, &quot;common_prefix&quot;: true, &quot;annotations&quot;: {&quot;content&quot;: &quot;price&quot;}}">
<td>Price</td><td>&pounds;85.00</td>
</tr>
</tbody></table>
</body></html>
"""
EXTRACT_PAGE10a = u"""
<html><body>
<table><tbody>
<tr>
<td>Offer</td><td>From $2500.00</td>
</tr>
<tr>
<td>Description</td><td>Electrorheological Cyborgs</td>
</tr>
<tr>
<td>Series:</td><td>T2000</td>
</tr>
</tbody></table>
</body></html>
"""
EXTRACT_PAGE10b = u"""
<html><body>
<table><tbody>
<tr>
<td>SKU</td><td>K80</td>
</tr>
<tr>
<td>Size</td><td>50cm</td>
</tr>
<tr>
<td>Price</td><td>&euros;85.00</td>
</tr>
</tbody></table>
</body></html>
"""
ANNOTATED_PAGE11 = u"""
<html><body>
<p data-scrapy-annotate="{&quot;variant&quot;: 0, &quot;annotations&quot;: {&quot;content&quot;: &quot;description&quot;}}">
@ -868,35 +804,6 @@ TEST_DATA = [
'price': [u'\n12.00\n(VAT exc.)'],
}
),
# detection of common prefixes across templates, all templates marked
(# wrong extraction
'without_match_common_prefix', [ANNOTATED_PAGE10a], EXTRACT_PAGE10a, None,
{
'price': [u'\n Series: T2000 \n'],
'dimensions': [u'\n Description Electrorheological Cyborgs \n'],
'site_id': [u'\n Offer From $2500.00 \n'],
}
),
(# right extraction
'with_match_common_prefix', [ANNOTATED_PAGE10a, ANNOTATED_PAGE10b], EXTRACT_PAGE10a, None,
{}
),
(# another example
'match_common_prefix', [ANNOTATED_PAGE10a, ANNOTATED_PAGE10b], EXTRACT_PAGE10b, None,
{
'dimensions': [u'50cm'],
'site_id': [u'K80'],
}
),
(# common_prefix with allow_markup attribute
'common_prefix_allow_markup', [ANNOTATED_PAGE10a, ANNOTATED_PAGE10b], EXTRACT_PAGE10b,
ItemDescriptor('test', 'product test',
[A('dimensions', "something about dimensions", allow_markup=True)]),
{
'dimensions': [u'50cm</td>'],
'site_id': [u'K80'],
}
),
(# special case with partial annotations
'special_partial_annotation', [ANNOTATED_PAGE11], EXTRACT_PAGE11, None,
{

View File

@ -34,7 +34,7 @@ LABELLED_PAGE1 = u"""
This is such a nice item<br/>
Everybody likes it.
</p>
<p data-scrapy-annotate="{&quot;variant&quot;: 0, &quot;common_prefix&quot;: true, &quot;annotations&quot;: {&quot;content&quot;: &quot;price&quot;}}"/>
<p data-scrapy-annotate="{&quot;variant&quot;: 0, &quot;annotations&quot;: {&quot;content&quot;: &quot;price&quot;}}"/>
\xa310.00
<br/>
<p data-scrapy-annotate="{&quot;variant&quot;: 0, &quot;annotations&quot;: {&quot;content&quot;: &quot;short_description&quot;}}">
@ -220,19 +220,6 @@ class TestPageParsing(TestCase):
self.assertEqual(len(lp.annotations), 5)
self._validate_annotation(lp, lp.annotations[0],
'name', '<h1>', '</h1>')
self.assertEqual(lp.annotations[0].match_common_prefix, False)
self._validate_annotation(lp, lp.annotations[1],
'description', '<p>', '</p>')
self.assertEqual(lp.annotations[1].match_common_prefix, False)
self._validate_annotation(lp, lp.annotations[2],
'price', '<p/>', '<p>')
self.assertEqual(lp.annotations[2].match_common_prefix, True)
self._validate_annotation(lp, lp.annotations[3],
'short_description', '<p>', '<p>')
self.assertEqual(lp.annotations[3].match_common_prefix, False)
self._validate_annotation(lp, lp.annotations[4],
'short_description', '<p>', '<p>')
self.assertEqual(lp.annotations[4].match_common_prefix, False)
# all tags were closed
self.assertEqual(len(lp.labelled_tag_stacks), 0)