Jump to content

Recipe/Ingredient taxonomy/Ingredient linking

From Open Food Facts wiki

Ingredient linking describes how the links between an ingredient in the ingredients taxonomy is linked to an entry in a food composition database.

Property format

In the ingredients taxonomy and entry (ingredient) consists of a list of ingredients names per language (and possible synonyms) as they are found on packaging. In addition to this language list a list of properties follow. These properties help in linking to other databases (like wikidata, wikipedia), whether the ingredient is vegan, etc.

In order to link to a food composition database a specific format is chosen. The general format for the property is:

<databases-identifier>_<fieldname>:<language>:

The database identifier describes the food composition database that is referenced:

  • ciqual_food for the french Ciqual database;
  • ifct for the Indian Food Composition tables;
  • usda - for the usa database;

The fieldname describes which kind of content is to be expected:

  • code - an unique identification code of the ingredient that is used in the food composition database;
  • name - a more readable name of the ingredient of the ingredient in the food composition database;

The field language gives the two letter ISO language that is used for the fieldname (only the name). Used are:

  • en - for english;
  • fr - for french;

Examples

An example:

ciqual_food_code:en: 16128
ciqual_food_name:en: Frying oil
ciqual_food_name:fr: Huile pour friture, sans précision

These three properties describe the link to the Ciqual database for the ingredient frying oil (en:frying-oil in the taxonomy). The code in the database is 16123, the english name frying oil and the french name Huile pour friture, sans précision. The french name is a bit more descriptive than the english name in the it states that the entry is for any frying oil, without an oil type specification.

Another example:

usda_ndb_code:en: 4589
usda_ndb_name:en: Fish oil, cod liver

These two properties describe the ingredient 4589 in the USDA Legacy food database. It is a specific variant for fish oil, i.e. cod liver fish oil. There is only an english name associated with this entry.

OFF-database matching

Ingredients found in nutritional databases (NDB) are not always easy to match to the ingredients in the OFF-ingredients taxonomy. The ingredients taxonomy should only contain words (ingredients) found on product ingredient lists. Matching implies that the words used in the taxonomy and NDB need to be compared. There is no formal definition for each ingredient. In order to match OFF-ingredients with NDB-ingredients a set of standard rules has been defined, depending on the situation.

Exact matches

The easiest situation is when there is an exact match between OFF ingredient and NDB ingredient. The words used for the ingredient are then exactly the same. Examples are the en:cod liver fish oil and en:frying oil mentioned above. There can be no doubt what is meant by the words used.

Missing NDB-ingredients

Some ingredients in the taxonomy do not have any match with any database. This might be due to a geographical bias of the database for instance. The ingredient might however resemble an other NDB-ingredient in terms of nutritional values. This can be used as a proxy ingredient.

For instance en:green pepper has not yet a matching NBD match. These are the berries of Piper nigrum, but not yet dried. In this case black pepper might be a (bad - due to different humidity levels) proxy. This can be encoded in the ingredients taxonomy as:

usda_ndb_proxy_code:en: 2030 
usda_ndb_proxy_name:en: Spices, pepper, black

Default matches

In many cases the OFF ingredient is underspecified with respect to a NDB-ingredient. NDB-ingredients often have additional adjective raw, uncooked, unprocessed, fresh etc. This extra adjective is not often mentioned on ingredients lists. It is assumed that all ingredients in the ingredients taxonomy underwent minimal processing before they were used in a recipe. This will be used as the default matching.

Thus for instance the ingredient en:sorghum is assumed to be the same as Sorghum, whole, raw in the USDA NDB, i.e. nothing has been done to the grains. This can be encoded as:

ciqual_food_code:en: 9360
ciqual_food_name:en: Sorghum, whole, raw
ciqual_food_name:fr: Sorgho entier, cru

Although unprocessed ingredients seem to be the best default, it also depends what is mostly used in a recipe. Thus another ingredient might be a better default [example needed].

Underspecified ingredients

An OFF-ingredient can be underspecified. The OFF-ingredient en:tamarind is named in Ciqual as raw tamarind pulp from immature fruit. As no alternate entry is available, we assume this is actually what is mean on ingredient lists.

Processed ingredients

In the ingredients taxonomy the choice has been made to suppress processed ingredients and only list the ingredient itself. This is done in order to reduce the number of entries. So there are no entries for diced tomatoes, diced cucumber, diced carrots, etc in all languages.

During parsing of the ingredient lists the processes of the processed ingredients are extracted based on the ingredients processing taxonomy.

Some entries in a NDB might list the processed variant of an ingredient. For instance en:turmeric can only be found as ground turmeric or powdered turmeric. To express this it is possible to add an extra line to the ingredient taxonomy entry, like:

ifct_food_code:en: G033
ifct_food_name:en: Turmeric powder
ifct_food_process:en: en:ground

Any processing that the parser picks up can thus be matched to the NBD as well. In the en:tamarind case this might be superfluous and does not add much extra.

Alternate processed ingredients

Some ingredients can be associated with multiple processes: for instance en:parsley has an entry fresh and dried in the USDA-database. As fresh comes closes to the original ingredient it can be set as default. As it is undesirable to create a specific entry for en:dried parsley, it can be added as associated entry to the taxonomy entry. This can be encoded in the taxonomy as:

usda_ndb_code:en: 11297
usda_ndb_name:en: Parsley, fresh
usda_ndb_process:en: en:fresh
usda_ndb_2_code:en: 2029
usda_ndb_2_name:en: Spices, parsley, dried
usda_ndb_2_process:en: en:dried

The recipe estimator can use this to iterate through the alternatives to find out which usda entry gives the best results.

Other examples are:

  • Ciqual
    • Rutabaga: raw, cooked
    • Salsify: raw, cooked;
  • USDA
    • daikon radish: raw and dried;
    • sweet potato: raw and frozen;
    • spirulina: dried and cooked;

Genuine alternate ingredients

Finally there might be genuine different variants of the same ingredient. These are ones that are determined by any specific process. For instance the USDA NDB has entries for en:Medjool dates and for en:Deglet noor dates, but no generic entry for dates like in Ciqual. By trying these alternate variants the recipe estimator can determine which one fits bests to a date entry in an ingredient list.

Other examples:

  • radish: black radish, red radish, daikon, white icicle radish

TODO: how can the recipe estimator know that there are alternatives. We could name the default one a proxy?

Inherited ingredients

If an ingredient has no link to nutritional database, there might be a substitute. If the ingredient has a (nutritional) parent, then the nutritional information of the parent can be used. Or its parent, etc.

Orphaned ingredients

The orphaned ingredients are those in the taxonomy for which there is no link to an entry in any nutritional database.

Statistics

Some statistics of the ingredients taxonomy linking (situation 20 july 2026).

Basic stats

Hierarchy structure

  • 4,772 total nodes (4,763 raw en: entries + 9 synthetic E-number/"additives" nodes created by the script)
  • 221 root categories
  • 3,506 leaf nodes / 1,266 nodes with children
  • 595 nodes with more than one parent (multi-parent)
  • Max depth: 7 levels
  • Depth distribution: 221 roots → 1,019 (d1) → 1,591 (d2) → 1,324 (d3) → 449 (d4) → 103 (d5) → 15 (d6) → 1 (d7)

Largest root categories by total descendant

  • vegetable — 549
  • fruit — 546
  • dairy — 317
  • cereal — 230
  • oil and fat — 206
  • flavouring — 189
  • fish — 188
  • plant — 181
  • added sugar — 154
  • animal — 121

Ciqual stats

How well can we map the ingredients in the taxonomy to the various nutritional databases?

Category Count % Definition
Exact match 820 17.2% Node itself carries a ciqual_food_code
Proxy match 159 3.3% Node itself carries a ciqual_proxy_food_code (no exact code)
Multiple ciquals 0 0.0% Node carries two different Ciqual code numbers
Alternate match 167 3.5% No own code, but ≥1 direct child has an exact/proxy match
Inherited match 1,869 39.2% No own/child match, but an ancestor up the tree has one
No match 1,757 6.8% No code anywhere in the node's own entry, children, or ancestors

IFCT

Category Count % Definition
Exact match 64 1.34% Node itself carries an ifct_food_code
Proxy match 1 0.02% Node itself carries an ifct_proxy_food_code (no exact)
Multiple ciquals 0 0.0% Node carries two different IFCT code values
Alternate match 36 0.75% No own code, but ≥1 direct child has an exact/proxy match
Inherited match 248 5.20% No own/child match, but an ancestor up the tree has one
No match 4,423 92.69% No code anywhere in the node's own entry, children, or ancestors

USDA

Category Count % Definition
Exact match 587 12.30% Node itself carries a usda_ndb_code
Proxy match 236 4.95% Node itself carries a usda_ndb_proxy_code (no exact)
Multiple ciquals 2 0.04% Node carries two different USDA codes
Alternate match 152 3.19% No own code, but ≥1 direct child has an exact/proxy match
Inherited match 786 16.47% No own/child match, but an ancestor up the tree has one
No match 3,009 63.06% No code anywhere in the node's own entry, children, or ancestors