Wikidata query service

From Wikitech
Jump to navigation Jump to search
Wikidata Query Service components
Wikidata Query Service components

Wikidata Query Service is the Wikimedia implementation of SPARQL server, based on Blazegraph engine, to service queries for Wikidata and other data sets. Please see more detailed description in the User Manual.

See also

Development environment

You will need java and maven, java can be installed from:


The source code is in gerrit project wikidata/query/rdf. In order to start working on Wikidata Query Service codebase, clone this repository:

git clone 

or github mirror:

git clone

or if you want to push changes and have a Gerrit account:

git clone ssh:// 

After update submodules:

$ cd wikidata-query-rdf
[../wikidata_query_rdf]$ git submodule update --init
Submodule 'gui' ( registered for path 'gui'


Then you can build the distribution package by running:

cd wikidata-query-rdf
./mvnw package

and the package will be in the dist/target directory. Or, to run Blazegraph service from the development environment (e.g. for testing) use:

bash war/

Add "-d" option to run it in debug mode. If your build is failing cause your version of maven is a different one you can:

 mvn package -Denforcer.skip=true

In order to run Updater, use:

 bash tools/

The build relies on Blazegraph packages which are stored in Archiva, and the source is in wikidata/query/blazegraph gerrit repository. See instructions on Mediawiki for the case where dependencies need to be rebuilt.

See also documentation in the source for more instructions.

SPARQL endpoint is available under /sparql path, which internally redirects to /bigdata/namespace/wdq/sparql.

Build Blazegraph

If there are changes needed to Blazegraph source, they should be checked into wikidata/query/blazegraph repo. After that, the new Blazegraph sub-version should be built and WDQS should switch to using it. The procedure to follow:

  1. Commit fixes (watch for extra whitespace changes!)
  2. Update README.wmf with descriptions of which changes were done against mainstream
  3. Blazegraph source in master branch will be on snapshot version, e.g. 2.1.5-wmf.4-SNAPSHOT - set it to non-snapshot: mvn versions:set -DnewVersion=2.1.5-wmf.4
  4. Make local build: mvn clean; bash scripts/; mvn -f bigdata-war/pom.xml install -DskipTests=true
  5. Switch Blazegraph version in maim pom.xml of WDQS repo to 2.1.5-wmf.4 (do not push it yet!). Build and verify everything works as intended.
  6. Commit the version change in Blazegraph, push it to the main repo. Tag it with the same version and push the tag too.
  7. Run to deploy: mvn -f pom.xml -P deploy-archiva deploy -P Development; mvn -f bigdata-war/pom.xml -P deploy-archiva deploy -P Development; mvn -f blazegraph-war/pom.xml -P deploy-archiva deploy -P Development
  8. Commit the version change in WDQS, and push to gerrit. Ensure the tests pass (this would also ensure Blazegraph deployment to Archiva worked properly).
  9. After merging the WDQS change, follow the procedure below to deploy new WDQS version.
  10. Bump Blazegraph master version back to snapshot - mvn versions:set -DnewVersion=2.1.5-wmf.5-SNAPSHOT - and commit/push it.



We're currently running on the following servers:

  • public cluster, eqiad: wdqs1004, wdqs1005, wdqs1006, wdqs1007
  • public cluster, codfw: wdqs2001, wdqs2002, wdqs2003, wdqs2007
  • internal cluster, eqiad: wdqs1003, wdqs1008
  • internal cluster, codfw: wdqs2004, wdqs2005, wdqs2006, wdqs2008

These clusters are in active/active mode (traffic is sent to both), but due to how we route traffic with GeoDNS, the primary cluster (usually eqiad) sees most of the traffic.

Server specs are similar to the following:

  • CPU: dual Intel(R) Xeon(R) CPU E5-2620 v3
  • Disk: 1600GB raw raided space SSD
  • RAM: 128GB


Icinga group

Grafana dashboard:

Grafana frontend dashboard:

WDQS dashboard:



The source code is in the Gerrit project wikidata/query/rdf (GitHub mirror). The GUI source code is Gerrit project wikidata/query/gui (GitHub mirror), which is also a submodule of the main project.

The deployment version of the query service is in the Gerrit project wikidata/query/deploy, with the deployment version of the GUI, wikidata/query/gui-deploy (production branch), as a submodule.

Labs Deployment

Note that currently deployment is via git-fat (see below) which may require some manual steps after checkout. This can be done as follows:

  1. Check out wikidata/query/deploy repository and update gui submodule to current production branch (git submodule update).
  2. Run git-fat pull to instantiate the binaries if necessary.
  3. rsync the files to deploy directory (/srv/wdqs/blazegraph)

Use role role::wdqs::labs for installing WDQS. You may also want to enable role::labs::lvm::srv to provide adequate diskspace in /srv.

Command sequence for manual install:

git clone
cd deploy
git fat init
git fat pull
git submodule init
git submodule update
sudo rsync -av --exclude .git\* --exclude scap --delete . /srv/wdqs/blazegraph

Production Deployment

Production deployment is done via git deployment repository wikidata/query/deploy. The procedure is as follows:

Initial Preparation

Preferred option: from Jenkins

  1. Log into Jenkins
  2. Go to
  3. Select build with parameters

Note: If the job fails, the archiva credentials could have changed, see here:

Fallback option: from your own machine

  1. ./mvnw -Pdeploy-archiva release:prepare in the source repository which updates the version numbers. If your system username is different that the one in scm, use -Dusername=... option.
  2. ./mvnw -Pdeploy-archiva release:perform in the source repository - this deploys the artifacts to archiva.

Note that for the above you will need repositories archiva.releases and archiva.snapshots configured in ~/.m2/settings.xml with archiva username/password. You will also need to have a gpg key setup.

Further required preparation

Prepare and submit the patch containing the new code updates:

  1. Run <target version> script - it will create a commit with newest version of jars + most up to date gui version.
  2. Using the commit generated by the above, open up a patch, and get it approved and merged.

Test that the service is working as expected before we mutate it with a deploy, so that we can compare properly:

  1. Open up a tunnel to the current wdqs canary instance via ssh -L 9999:localhost:80 wdqs1003.eqiad.wmnet (check that wdqs1003 is still the canary)
  2. Run the test script through the tunnel: from the rdf repo, run cd queries && ./ -s http://localhost:9999/
  3. You may also want to navigate to http://localhost:9999 and run an example query.

Now we're ready for the actual deploy!

The actual code deploy

On the deployment server, cd into cd /srv/deployment/wdqs/wdqs. First we'll get the repo into the desired state, then do the actual deploy.

  1. First git fetch, then glance at git log HEAD...origin/master and manually verify the expected commits are there, then git rebase && git fat pull
  2. Now that the repo is in the desired state, sanity check with ls -lah that you see the .war file and that it doesn't seem absurdly small
  3. Use scap deploy '<the latest version number>' to deploy the new build. After canary deployment will be done (scap will as for confirmation to proceed), please test the service. You can do that by ssh tunneling access to

wdqs1003.eqiad.wmnet and running ./ -S localhost:<tunneled_port> script from `queries` subproject (keep in mind that badservice.sparql is meant to fail and orderby.sparql can fail because of the timeout - TODO: rewrite orderby.sparql query is it doesn't timeout)

  1. Validation #1: In a separate pane or tab, navigate to and run/look at scap deploy-log
  2. Validation #2: In yet another separate pane, tail the logs on the wdqs canary via tail -f /var/log/wdqs/wdqs-updater.log -f /var/log/wdqs/wdqs-blazegraph.log (Note we're tailing two log files at once so results will be interleaved)
  3. Once the canary deployment looks good, proceed to the rest of the fleet by pressing c

Post code-deploy operational steps

These steps have been separated into a separate subsection from the actual code deploy, but these steps are a mandatory part of the deploy, just to be clear.

  1. Restart wdqs-updater after the deployment is complete: sudo -E cumin -b 4 'A:wdqs-all' 'systemctl restart wdqs-updater' (Note that wdqs-updater can be safely restarted without user impact)
  2. Restart wdqs-categories one in-service node at a time (restarting it on a pooled node impacts users and thus requires depooling), like so: sudo -E cumin -b 1 'A:wdqs-all and not A:wdqs-test' 'depool && sleep 60 && systemctl restart wdqs-categories && sleep 15 && pool'
  3. Restart the remaining wdqs-test nodes, which aren't pooled and therefore we can't use the above command: sudo -E cumin 'A:wdqs-test' 'systemctl restart wdqs-categories'

General puppet note (nothing to do here for a deploy): The puppet role that needs to be enabled for the service is role::wdqs.

It is recommended to test deployment checkout on beta before deploying it in production. The test script is located at rdf/query/

GUI deployment general notes

GUI deployment files are in repository wikidata/query/gui-deploy branch production. It is a submodule of wikidata/query/deploy which is linked as gui subdirectory. script will take care of updating it, along with the deployment version.

New deployment GUI versions are automatically built by WDQSGuiBuilder after every merge in the wikidata/query/gui repo, so usually you can just +2 them (query). You can also run grunt deploy in the GUI directory to generate such a patch by hand (which still needs to be merged manually). Either way, after the gui-deploy repo has been updated, update the submodule gui on wikidata/query/deploy to latest production head and commit/push the change. Deploy as per above.

Note the steps in the above sections (not this one) include using which performs a submodule update, so the steps for updating the guisubmodule should only be necessary for cases where that script was not used. That is to say, if having followed the steps in the Production_Deployment, there shouldn't be anything in this section that needs to be done.

Data reload procedure

Data preparation

This can be done while services are running and does not require any downtime. Ensure that there's enough disk space on /srv/wdqs or use other space for the files. Space required is around 2.5x the size of the compressed dump, or currently around 100G.

  1. Download latest Wikidata dump: or (Wikimedia downloads are bandwidth-limited so using a mirror may be faster)
  2. Download latest Lexeme dump:
  3. Create /srv/wdqs/munged and /srv/wdqs/lex-munged
  4. Run munger for main database: bash -f latest-all.ttl.bz2 -d /srv/wdqs/munged
  5. Run munger for lexemes: bash -f latest-all.ttl.bz2 -d /srv/wdqs/lex-munged

Data loading

This is the procedure for reloading main service. See the procedure for categories service below.

  1. Go to icinga and schedule downtime:
  2. Depool: HOME=/root sudo depool
  3. Remove data loaded flag: rm /srv/wdqs/data_loaded
  4. Stop the updater: sudo service wdqs-updater stop
  5. Turn on maintenance: touch /var/lib/nginx/wdqs/maintenance
  6. Stop Blazegraph: sudo service wdqs-blazegraph stop
  7. Remove old db: rm /srv/wdqs/wikidata.jnl
  8. Start blazegraph: sudo service wdqs-blazegraph start, check that /srv/wdqs/wikidata.jnl is created.
  9. Check logs: sudo journalctl -u wdqs-blazegraph -f and less /var/log/wdqs/wdqs-blazegraph.log.
  10. Load data: bash -n wdq -d /srv/wdqs/munged
  11. Load lexeme dump: curl -XPOST --data-binary update="LOAD <file:///srv/wdqs/lex-munged/wikidump-000000001.ttl.gz>" http://localhost:9999/bigdata/namespace/wdq/sparql
  12. Restore data loaded flag: touch /srv/wdqs/data_loaded
  13. Start updater: sudo service wdqs-updater start
  14. Check logs: sudo journalctl -u wdqs-updater -f
  15. Wait for the updater to catch up - look at /var/log/wdqs/wdqs-updater.log
  16. Repool: HOME=/root sudo pool

Categories reload procedure

Categories are now living in a separate service, so should not be reloaded together with main service.

This process has been operationalized as the cookbook with the option --reload-data categories.

  1. Depool: HOME=/root sudo depool
  2. Stop categories service: sudo service wdqs-categories stop
  3. Remove old db: rm /srv/wdqs/categories.jnl
  4. Start blazegraph: sudo service wdqs-categories start, check that /srv/wdqs/categories.jnl is created.
  5. Check logs: sudo journalctl -u wdqs-categories -f and less /var/log/wdqs/wdqs-categories.log.
  6. Reload categories from weekly dump: /usr/local/bin/ or if needed to be done manually: bash categories; bash categories
  7. Reload daily diffs:
    1. For the day next to the weekly dump's day: {TS} fromDump{WEEKLYTS}-, where TS is next day's date, YYYYMMDD format, and WEEKLYTS is the date of the weekly dump (would be one day earlier than TS). E.g.: 20181007 fromDump20181006-. Note the dash at the end of the prefix.
    2. For each following day: {TS} where TS is the day of the diff. E.g. 20181008.
    3. If possible, it is recommended to reload the data close to the date of the weekly dump, to minimize amount of dailies that are needed to load. As an alternative, one can perform weekly reload as soon as the new weekly dump is ready.
  8. Repool: HOME=/root sudo pool

Data transfer procedure

Transferring data from between nodes is typically faster than recovering from a dump. The port 9876 is opened between the wdqs nodes of the same cluster for that purpose. Across different clusters, that port needs to be opened manually (and closed after the opertation). The procedure is automated in a cookbook (text in BOLD needs to be adapted):

  1. on the destination node, open a port if needed: sudo iptables -A INPUT -p tcp -s wdqs1010.eqiad.wmnet --dport 9876 -j ACCEPT
  2. copy the main data: sudo -i cookbook --source wdqs1010.eqiad.wmnet --dest wdqs2007.codfw.wmnet --without-lvs --blazegraph_instance blazegraph --reason "reloading data from wdqs1010 to wdqs2007 - some reason" --task-id T246343
  3. copy the categories data: sudo -i cookbook --source wdqs1010.eqiad.wmnet --dest wdqs2007.codfw.wmnet --without-lvs --blazegraph_instance categories --reason "reloading data from wdqs1010 to wdqs2007 - some reason" --task-id T246343
  4. on the destination node, close the port if needed: sudo iptables -D INPUT -p tcp -s wdqs1010.eqiad.wmnet --dport 9876 -j ACCEPT

Note: By default the cookbook will depool / pool nodes automatically. The --without-lvs argument prevents this. This affects both source and destination, so in the case where the source is not behind LVS but the destination is, depooling / pooling must be done manually.

Potential improvements to the cookbook:

  • open and close ports automatically
  • iterate over multiple destination servers
  • iterate over multiple data files (blazegraph / categories)
  • supports different depooling strategies for source and destination
  • wait for server to catchup on lag before repooling / terminating the cookbook

Updating federation whitelist

Manually updating entities

It is possible to update single entity or a number of entities on each server, in case data gets out of sync. The command to do it is:

 cd /srv/deployment/wdqs/wdqs; bash -n wdq -N -S -- -b 500 --ids Q1234 Q5678 ...

In order to do it on all servers at once, commands like pssh can be used:

 pssh -t 0 -p 20 -P -o logs -e elogs -H "$SERVERS" "cd /srv/deployment/wdqs/wdqs; bash -n wdq -N -S -- -b 500 --ids $*"

Where $SERVERS would contain the list of servers updated. Note that since it is done via command line, updating larger batches of IDs will need some scripting to split them into manageable chunks. Doing bigger updates at moderate pace, with pauses to not interfere with regular updates, is recommended.

Updating IDs by timeframe

Sometimes, due to some malfunction, a segment of updates for certain time period gets lost. If it's a recent segment, updater can be reset to start with certain timestamp by using --start TIMESTAMP --init (you have to shut down regular updater, reset the timestamp, and then start it again). If the missed segment is in the past, the best way is to fetch IDs that were updated in that time period, using Wikidata recentchanges API, and then update these IDs as described above.

Example of such script can be found here: The output should be filtered and duplicates removed, then fed to a script calling to update script as per above.

Updating value or reference nodes

Since value (wdv:hash) and reference (wdref:hash) nodes are supposed to be immutable, they will not be touched by updates to items that use them. To fix these nodes, you need to delete all triples with these nodes as the subject (SPARQL DELETE through production access), then trigger an update (as above) for items which reference these nodes (so they will be recreated; only one item per node necessary).


Scaling strategy



If you need more info, talk to User:Smalyshev, User:Gehel or anybody from mw:Discovery team.