Rebuild PostgreSQL Search Dictionaries with pg_updatedicts
Use pg_updatedicts to turn installed Hunspell or Myspell dictionaries into the UTF-8 files that Debian PostgreSQL uses for text search and word stemming. The command refreshes a shared cache and creates links for each installed PostgreSQL version. This guide takes about 10 minutes, including verification.
The route
Jump straight to the step you need, or tick off Done means at the end.
Before you start
This is Debian's postgresql-common utility. On the machine used for these examples, the package version is 257build1.1, and the command is /usr/sbin/pg_updatedicts. The installed manpage is dated 9 August 2024. The implementation also searches /usr/share/hunspell, although the manpage describes the traditional /usr/share/myspell/dicts/ location.
You need root privileges because the command writes below /var/cache/postgresql/dicts/ and /usr/share/postgresql/. It does not take a dictionary name, an output directory, or any other option: the complete command is:
sudo /usr/sbin/pg_updatedicts
Have a PostgreSQL package and at least one matching dictionary package installed if you expect files to be built. The command does not install dictionaries itself. It is normally run automatically by the postgresql-common dpkg trigger when a Hunspell or MySpell dictionary is installed or upgraded.
1. Check the inputs and PostgreSQL targets
First, inspect the source directories and the PostgreSQL text-search directories. These checks do not change anything.
find /usr/share/hunspell /usr/share/myspell/dicts -maxdepth 1 \
\( -name '*.aff' -o -name '*.dic' \) -type f -print 2>/dev/null
find /usr/share/postgresql -maxdepth 2 -type d -name tsearch_data -print 2>/dev/null
Each usable dictionary needs both files, such as en_US.aff and en_US.dic. The script ignores a symbolic-link .aff file, reports an error for an .aff without its matching .dic, and reports an error if the affix file has no SET encoding line. A missing source directory is not itself proof that PostgreSQL is broken; it usually means no dictionary package has supplied that location.
Checkpoint
Record the source file names and the PostgreSQL versions printed by the two commands. You will compare them with the generated links.
2. Run the rebuild as root
Run the command once. It converts each accepted pair to UTF-8, using the locale name in lower case. The cache names end in .affix and .dict, not the input suffixes.
sudo /usr/sbin/pg_updatedicts
Normal output starts like this:
Building PostgreSQL dictionaries from installed myspell/hunspell packages...
en_us
Removing obsolete dictionary files:
The locale line is an example, not a promise that en_us is installed. With no usable dictionaries, the headings can appear with no locale entries. A conversion failure is reported on standard error and the incomplete output is removed.
Warning
This is a synchronising command. After processing current inputs, it removes obsolete generated files from the cache and obsolete generated symbolic links from PostgreSQL tsearch_data directories. Do not place hand-maintained files in those generated locations. Put the original dictionary files in the package-managed source directory, then rerun the command to recover the generated state.
3. Verify the cache and links
Check the cache first. The names and contents are generated by the command, so do not edit them directly.
sudo find /var/cache/postgresql/dicts -maxdepth 1 -type f \
\( -name '*.affix' -o -name '*.dict' \) -printf '%f\n' | sort
For every accepted input pair, expect one .affix and one .dict file. The affix file and dictionary file are both converted to UTF-8. A missing pair usually points to an absent source file, an affix file without SET, an unsupported encoding, or a failed write.
Now inspect the links for each installed PostgreSQL version:
find /usr/share/postgresql -path '*/tsearch_data/*.affix' -o \
-path '*/tsearch_data/*.dict' -type l -printf '%p -> %l\n' | sort
Because shell precedence makes that compact form easy to misread, this clearer loop is preferable when diagnosing a result:
while IFS= read -r dir; do
printf '%s\n' "$dir"
find "$dir" -maxdepth 1 -type l -printf ' %f -> %l\n' | sort
done < <(find /usr/share/postgresql -maxdepth 2 -type d \
-name tsearch_data -print | sort)
Each link should point into /var/cache/postgresql/dicts/. Existing non-symbolic files in a target directory are preserved rather than replaced. That protects a locally managed file, but it can also leave PostgreSQL using an older file, so investigate any same-named regular file before declaring the rebuild complete.
4. Connect the result to text search
pg_updatedicts makes dictionary files available to PostgreSQL; it does not create a text search configuration or change a database. PostgreSQL configurations and dictionaries refer to the generated base name. For example, a generated en_us.dict is the file that a text search dictionary definition can use as its template, subject to the configuration you choose.
Keep the operational checks separate from SQL configuration. First confirm that the files and links exist, then test the database configuration with the relevant PostgreSQL SQL commands. A successful rebuild alone does not prove that an application is using the intended text search configuration.
5. Diagnose and recover
If the command exits unsuccessfully, read both output streams and check the paths before changing permissions. The most useful checks are:
sudo test -d /var/cache/postgresql/dicts && echo cache-present
namei -l /var/cache/postgresql/dicts
namei -l /usr/share/postgresql/16/tsearch_data
Replace 16 with a version printed in step 1. Permission errors, unwritable filesystems, and failed iconv conversions need fixing at their source. Do not copy generated files by hand or change the PostgreSQL service configuration to compensate.
If a dictionary package was repaired, reinstalled, or upgraded, rerun sudo /usr/sbin/pg_updatedicts. That is the undo path for a failed or incomplete generated state: the command rebuilds from the current source files and recreates the links. If a source package was removed deliberately, rerunning also removes its generated cache files and links, which is expected.
Done means
- The expected
.affand.dicinputs exist in a supported source directory. pg_updatedictscompleted without an error for the dictionaries you need.- The cache contains matching UTF-8
.affixand.dictfiles. - Each PostgreSQL
tsearch_datadirectory has links to the corresponding cache files. - Your SQL text search configuration has been tested separately.