Powered by Zoomin Software. For more details please contactZoomin

The Semaphore Fact Extraction Framework (FACTS)

The SELECT_TAG rule

  • Last Updated: August 14, 2026
  • 6 minute read
    • Semaphore
    • Documentation

The SELECT_TAG rule will fire if there are any taggedPhraseRanges passed up to the rule with a match (case sensitive) of tag name and data for the rule. It will also propagate the matching taggedPhraseRange and any further taggedPhraseRanges which are grouped by this matching taggedPhraseRange.

Score calculation

Scores its weight if any matching taggedPhraseRanges found

Evidence calculation

The matching taggedPhraseRanges converted back to normal phraseRanges evidence

Attribute information

  • any attribute
  • FOREACH
  • WEIGHT - Is an absolute weight not scaling
  • DATA - Gives the name of the tag to select - NB it only searches the taggedPhraseRanges which bubble up to the rule

Children restrictions

Any rule other than those restricted to a specific parent

Whilst the actual behaviour of this rule is simple to state, as above, it might be difficult to see how this rule is useful and why it exists. The SELECT_TAG rule arose out of trying to solve problems with the SELECT rule. However the SELECT_TAG is a much more general rule and may be used in many situations other than as a replacement for SELECT.

The problem that the SELECT rule was trying to address was the difficulty that arises when you intersect 2 (or more) sets of phrase ranges rather than 2 (or more) sets of tokens. Since phrase ranges have a length the meaning of an intersection is more complex. Two phrase ranges can partially or fully (or any combination thereof) intersect.

The INTERSECTION rule answers this simply by returning only the actual intersection (so the parts of the intersecting range which actually exists in both). Unfortunately, often we want to use an intersection as a way of selecting / filtering a larger set.

So for example you might have a set of peoples names found in a document but for some reason wanting to filter this list to find only those names containing the title “Mr”

    <phrase label="full_name" >
       <expression type="TITLE" />
       <expression type="PERSON" />
    </phrase>
    <intersection>
          <link label="full_name" />
          <text data="Mr" />
    </intersection>

The problem with this is that the actual intersection set itself is simply a subset of “Mr” tokens which happen to occur within the identified “full_name” phrases. In many cases you are actually interested in selecting the full name rather than just the intersection.

SELECT was an attempt to solve this in that it returned both intersecting phrase ranges - so you had “Mr” and “Mr Smith” (but not say “Mrs Smith”) in the resulting evidence set.

In many cases this was sufficient especially if you wrap this in a UNION so that the “Mr” and “Mr Smith” are merged into a single phrase range. However in some cases it is important to retain the original phrase range set and not apply the union at this stage.

For example if the full_name set had overlapping evidence “Mr Smith” and “Mr Smith-Jones” for some reason then applying the UNION would only have “Mr Smith-Jones” as a phrase range. If this evidence set was then used as a start for a sequence

    <union label="selected_evidence" >
       <select>
          <link label="full_name" />
          <text data="Mr" />
       </select>
    </union>

    <sequence>
        <link label="selected_evidence" />
        <text data="Jones" />
    </sequence>

Since the “selected_evidence” has already had the UNION applied then this sequence would not fire. Whilst this is rather a contrived example this type of scenario occured reasonably frequently when using rules generated by the Fact Framework since that taks a more programmatic approach the the rule generation.

It turns out that in many cases we really want to pick the phrase range from one side of the intersection rather than both sides.

This selection from “one side” was already handled in a fairly generic manner by using extraction tagging

    <extract>
        <intersection>
              <link label="full_name" extract_name="person" />
              <text data="Mr" />
        </intersection>
     </extract>

So in this example the evidence for the “full_name” rule was tagged with the name “person”. Since taggedPhraseRanges are never rewritten / adjusted by rules higher in the calculation tree they are either passed up intact (bubbled) or discarded. So the taggedPhraseRange(Person) only reaches the EXTRACT rule if the particular phraseRange is involved in the INTERSECTION.

This gives us what we want (for extraction) in that

     ....
     <META name="PERSON" value="Mr Smith" />
     ...

Will appear in the output for the classification.

Having noticed that we had already solved the problem of selecting “one side” of an INTERSECTION by using extraction tags we decided to re-use this mechanism but make it available for use in other contexts than simply extraction.

     <select_tag data="person" >
        <intersection>
              <link label="full_name" extraction_name="person" />
              <text data="Mr" />
        </intersection>
     </select_tag>

So here the evidence list for the SELECT_TAG rule is simply the taggedPhraseRange “person” which has “bubbled” up through the intersection rule - ie it is selecting “one side” of the INTERSECTION as wanted.

In this case above we have used the extraction_name tag (simply because that was used in an earlier example). Various types of tags may be used during extraction - for the purposes of the SELECT_TAG rule this does not distinguish between types of tags (ie the type just has an impact on extraction itself). So for simplicity the previous example could just as well be.

     <select_tag data="select_me" >
        <intersection>
              <text data="Mr" />
              <link label="full_name" tag="select_me" />
        </intersection>
     </select_tag>

This would have identical behaviour in terms of the SELECT_TAG rule itself - the difference would only be shown if you then ended up doing an extraction higher up the tree (ie above the SELECT_TAG rule). At this point then the difference in tag type would impact the behaviour of the extraction - SELECT_TAG itself however will not care - it will just convert taggedPhraseRanges to phraseRanges regardless of the type of tag matched.

Example

   <select_tag data="select_me" >   
       <intersection>
           <link label="full_name" tag="select_me" />
           <any not="1" >
               <text data="Mr" />
               <text data="Mrs" />
               <text data="Ms" />
               <text data="Miss" />
           </any>
       </intersection>
   </select_tag>

   <phrase label="full_name" >
       <expression type="TITLE" />
       <expression type="PERSON" />
   </phrase>


This finds all people who have a title other than the given list as part of their name (and probably more reasonbly would be written by intersecting the <expression type=“TITLE” /> with the notted list before looking for the sequence TITLE PERSON but there may be cases where you want the full set of full_names for some purposes and it is much more efficient to re-use the found set and further restrict it rather than creating a new rule branch)

NB whilst the SELECT_TAG rule arose as a replacement for SELECT this is not limited to being used in INTERSECTION rules. Any arbitrarily complex ruletree may be used with SELECT_TAG just like extraction may. Of particular note (and possibly not immediately obvious) it is possible to use SELECT_TAG to rewrite extraction names for use in a different (or even the same) extraction with a slightly different purpose.

This can be of particular use when tagging is used lower in the tree to identify concepts which end up being extracted - but might need to be extracted again in a slightly different context

      <any label="aspirin" tag="http://example/some_heirarchy/drugs/aspirin" >
          <text data="aspirin" />
          <text data="salic acid" />
       </any>
       ...
       <any label="paracetamol" tag="http://example/some_hierarchy/drugs/paracetamol" >
           <text data="paracetamol" />
           ...
       </any>
       ...

Which is then grouped as an extraction named “DRUG” and then found in a document as part of a prescription (so with key words like “to be taken twice a day”)

    <any label="drugs" >
        <link label="aspirin" />
        <link label="paracetamol" />
        ...
    <any>
    
    <paragraph label="prescription" extract_group="PRESCRIPTION" >
        <link label="drugs" extract_tags="DRUG" />
        <link label="key_proscribing_vocabulary" />
        <link label="frequency" extract_name="FREQUENCY" />
        <link label="doctor" extract_name="PHYSICIAN" />
    </paragraph>

This prescription could now be passed to an EXTRACT rule to have a grouped PRESCRIPTION output.

However it might be the case that you needed to generate a list of PRESCRIBED_DRUGS for a document in addition to having these listed in their individual PRESCRIPTION extraction groups. Obviously this can be done by simply processing the extraction output however this might be simpler to do in rules by rewriting the “PRESCRIPTION::DRUG” extraction to a separate extraction. The key insight to doing this is to notice that intersecting <select_tag data=“DRUG”> with <link label=“drugs” /> would result in just the prescribed drugs in the document with a simple (ungrouped) tag which can then be rebound to a different extraction_tags and then just these rebound tags found by applying a second <select_tag>

    <extract>
        <select_tag data="PRESCRIBED_DRUG" >
            <intersection extract_tags="PRESCRIBED_DRUG" >
                 <select_tag data="DRUG" >
                   <link label="prescription" />
                  </select_tag>
                  <link label="drugs" />
            </intersection>
        </select_tag>
     </extract>
 
Alert