Development/Tutorials/Metadata/Nepomuk/TipsAndTricks: Difference between revisions
No edit summary |
|||
Line 1: | Line 1: | ||
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Metadata/Nepomuk/TipsAndTricks}} | {{Template:I18n/Language Navigation Bar|Development/Tutorials/Metadata/Nepomuk/TipsAndTricks}} | ||
{{TutorialBrowser| | {{TutorialBrowser| | ||
Line 7: | Line 7: | ||
[[../AdvancedQueries|Advanced Queries with SPARQL]], | [[../AdvancedQueries|Advanced Queries with SPARQL]], | ||
[[../RDFIntroduction|RDF and Ontologies in Nepomuk]] | [[../RDFIntroduction|RDF and Ontologies in Nepomuk]] | ||
}} | }} | ||
== Always initialize Nepomuk == | == Always initialize Nepomuk == | ||
<code cppqt> | Make sure that somewhere in the initialization code of your application or library Nepomuk is initialized via: | ||
<code cppqt="cppqt"> | |||
Nepomuk::ResourceManager::instance()->init(); | Nepomuk::ResourceManager::instance()->init(); | ||
</code> | </code> | ||
<br> | |||
== Using ontology URIs in your code == | |||
One often needs the URI of a specific class or a specific property in ones code. And not all ontologies are provided by the very convenient [http://soprano.sourceforge.net/apidox/stable/namespaceSoprano_1_1Vocabulary.html Soprano::Vocabulary] namespace. | |||
The solution is rather simple: create your own vocbulary namespaces by using Soprano's own onto2vocabularyclass command line tool. It can generate convenient vocabulary namespaces for you. The Soprano documentation shows how to [http://soprano.sourceforge.net/apidox/trunk/soprano_devel_tools.html use it manually] or even simpler with a [http://soprano.sourceforge.net/apidox/trunk/soprano_howto.html#cmake_magic simple CMake macro]. | |||
<br> | |||
== Mind the Difference between QString and QUrl == | |||
[http://api.kde.org/4.x-api/kdelibs-apidocs/nepomuk/html/classNepomuk_1_1Resource.html Nepomuk::Resource] provides two constructors: one taking a {{qt|QString}} as identifier or URI and one taking a {{qt|QUrl}}. | |||
[http://api.kde.org/4.x-api/kdelibs-apidocs/nepomuk/html/classNepomuk_1_1Resource.html Nepomuk::Resource] provides two constructors: one taking a {{qt|QString}} as identifier or URI and one taking a {{qt|QUrl}}. | |||
The latter one is really simple: the given URI is used as the resource URI. If the resource exists, its data is used, otherwise it will be created with exactly that URI. | The latter one is really simple: the given URI is used as the resource URI. If the resource exists, its data is used, otherwise it will be created with exactly that URI. | ||
The {{qt|QString}} one is a bit trickier. It will try to be clever about the parameter and see if it is a URI. If no resource with that URI (if it is a URI) exists, it is interpreted as an identifier ([http://www.semanticdesktop.org/ontologies/nao/#mozTocId802441 nao:identifier]). Resource checks if a resource with that identifier exists. If so, its data is loaded, if not, a new resource with a random URI and that string as identifier is created. | The {{qt|QString}} one is a bit trickier. It will try to be clever about the parameter and see if it is a URI. If no resource with that URI (if it is a URI) exists, it is interpreted as an identifier ([http://www.semanticdesktop.org/ontologies/nao/#mozTocId802441 nao:identifier]). Resource checks if a resource with that identifier exists. If so, its data is loaded, if not, a new resource with a random URI and that string as identifier is created. | ||
However, '''be aware that nothing is written to Nepomuk until the first writing call to Resource such as setProperty or addType.''' | However, '''be aware that nothing is written to Nepomuk until the first writing call to Resource such as setProperty or addType.''' | ||
<br> | |||
== Debugging the created data == | == Debugging the created data == | ||
=== Using sopranocmd === | |||
To access the Nepomuk storage one would typically use the D-Bus interface: | When using Nepomuk one creates a lot of RDF statements in the Nepomuk RDF storage. It is often of interest to check which data has been created, if statements have been correctly created or simply look at existing data. | ||
Soprano provides a nice command line client to do all this called ''sopranocmd''. It provides all the features one needs to debug data: it can add and remove statements, list and query them, import and export whole RDF files, and even monitor for ''[http://soprano.sourceforge.net/apidox/trunk/classSoprano_1_1Model.html#3e2595166caac3621fd4268e46049adf statementAdded]'' and ''[http://soprano.sourceforge.net/apidox/trunk/classSoprano_1_1Model.html#8fa85bfce2f83e89f83ef602cd818991 statementRemoved]'' events. | |||
To access the Nepomuk storage one would typically use the D-Bus interface: | |||
<code> | <code> | ||
# sopranocmd --dbus org.kde.NepomukStorage --model main <command> \ | # sopranocmd --dbus org.kde.NepomukStorage --model main <command> \ | ||
<parameters> | <parameters> | ||
</code> | </code> | ||
If one wanted to list all the resources that have been tagged with the tag whose resource URI is nepomuk:/foobar one would use the following command: | If one wanted to list all the resources that have been tagged with the tag whose resource URI is nepomuk:/foobar one would use the following command: | ||
<code> | <code> | ||
# sopranocmd --dbus org.kde.NepomukStorage --model main list \ | # sopranocmd --dbus org.kde.NepomukStorage --model main list \ | ||
"" "" "<nepomuk:/foobar>" | "" "" "<nepomuk:/foobar>" | ||
</code> | </code> | ||
or one would use a SPARQL query ('''sopranocmd supports the standard URI prefixes out of the box'''): | or one would use a SPARQL query ('''sopranocmd supports the standard URI prefixes out of the box'''): | ||
<code> | <code> | ||
Line 59: | Line 67: | ||
"select ?r where { ?r nao:hasTag ?tag . \ | "select ?r where { ?r nao:hasTag ?tag . \ | ||
?tag nao:prefLabel 'foobar'^^xsd:string . }" | ?tag nao:prefLabel 'foobar'^^xsd:string . }" | ||
</code> | </code> | ||
To monitor all statements that are added and removed from the Nepomuk storage one would simply use the following command (as with ''list'' one can specify a filter to only list the added and removed statements one is interested in): | To monitor all statements that are added and removed from the Nepomuk storage one would simply use the following command (as with ''list'' one can specify a filter to only list the added and removed statements one is interested in): <code> | ||
<code> | |||
# sopranocmd --dbus org.kde.NepomukStorage --model main monitor | # sopranocmd --dbus org.kde.NepomukStorage --model main monitor | ||
</code> | </code> | ||
<code># sopranocmd --help</code> is your friend for all details. | <code># sopranocmd --help</code> is your friend for all details. | ||
<br> ''Hint: add the following to your .bashrc to avoid having to type in the dbus and model parameters all the time:'' | |||
<code>alias nepomukcmd="sopranocmd --socket ${HOME}/.kde/share/apps/nepomuk/socket --model main --nrl $@"</code> | |||
''(Be aware that the --nrl parameter is only available in Soprano 2.3.63 and above.)'' | |||
=== Using Konqueror === | |||
In the [http://websvn.kde.org:80/trunk/playground/base/nepomuk-kde/kioslaves/nepomuk/ Nepomuk playground] repository lives a KIO slave which can handle the ''nepomuk:/'' protocol. It will display all properties of a Nepomuk resource including its links to other resources and the backlinks. This is a convenient way of looking at the Nepomuk data. The KIO slave even support removal of resources. | |||
In the [http://websvn.kde.org:80/trunk/playground/base/nepomuk-kde/kioslaves/nepomuk/ Nepomuk playground] repository lives a KIO slave which can handle the ''nepomuk:/'' protocol. It will display all properties of a Nepomuk resource including its links to other resources and the backlinks. This is a convenient way of looking at the Nepomuk data. The KIO slave even support removal of resources. | |||
[[ | [[Image:Nepomuk kio slave.png|560px]] | ||
<br> | |||
=== Using NepomukShell === | === Using NepomukShell === | ||
[ | The NepomukShell is another tool that lives in the [http://websvn.kde.org:80/trunk/playground/base/nepomuk-kde/nepomukshell playground]. It is a simple tool that let's one browse all resources in Nepomuk. Additionally it allows to create subclasses and properties ('''Caution: do only create subclasses and properties from PIMO classes and properties!''') and remove resources. | ||
[[Image:Pimoshell.png|560px]] | |||
== Constructing SPARQL queries == | |||
Whenever doing something a bit fancier with Nepomuk one has to use SPARQL queries via | '''Hint: In most cases the [http://api.kde.org/4.x-api/kdelibs-apidocs/nepomuk/html/namespaceNepomuk_1_1Query.html Nepomuk Query API] should be enough and prevent you from writing your own SPARQL which is hard to debug.''' | ||
<code cppqt> | |||
Whenever doing something a bit fancier with Nepomuk one has to use SPARQL queries via <code cppqt="cppqt"> | |||
Nepomuk::ResourceManager::instance()->mainModel() | Nepomuk::ResourceManager::instance()->mainModel() | ||
->executeQuery( myQueryString, | ->executeQuery( myQueryString, | ||
Soprano::Query::QueryLanguageSparql ); | Soprano::Query::QueryLanguageSparql ); | ||
</code> | </code> Constructing these queries can be a bit cumbersome since one has to use a lot of class and property URIs from different ontologies. Also literals have to be formatted according to the N3 syntax used in SPARQL. Luckily Soprano provides the necessary tools to do exactly that: [http://soprano.sourceforge.net/apidox/trunk/classSoprano_1_1Node.html#ad4c8ab988ae7d9fd587027087b593e4 Soprano::Node::toN3], [http://soprano.sourceforge.net/apidox/trunk/classSoprano_1_1Node.html#d1c2618a28a13c6eac042ddccbf78e6a Soprano::Node::resourceToN3], and [http://soprano.sourceforge.net/apidox/trunk/classSoprano_1_1Node.html#a66acf156e82b866114d90cd0c9ce13c Soprano::Node::literalToN3] take care of all formatting and percent-encoding you need. Using those methods the code to create queries might look ugly but the resulting queries are more likely to be correctly encoded and introduce less code duplication. | ||
Constructing these queries can be a bit cumbersome since one has to use a lot of class and property URIs from different ontologies. Also literals have to be formatted according to the N3 syntax used in SPARQL. Luckily Soprano provides the necessary tools to do exactly that: [http://soprano.sourceforge.net/apidox/trunk/classSoprano_1_1Node.html#ad4c8ab988ae7d9fd587027087b593e4 Soprano::Node::toN3], [http://soprano.sourceforge.net/apidox/trunk/classSoprano_1_1Node.html#d1c2618a28a13c6eac042ddccbf78e6a Soprano::Node::resourceToN3], and [http://soprano.sourceforge.net/apidox/trunk/classSoprano_1_1Node.html#a66acf156e82b866114d90cd0c9ce13c Soprano::Node::literalToN3] take care of all formatting and percent-encoding you need. Using those methods the code to create queries might look ugly but the resulting queries are more likely to be correctly encoded and introduce less code duplication. | |||
Typically one would use QString::arg like so (be aware that the standard prefixes are NOT supported out-of-the-box as with sopranocmd): | Typically one would use QString::arg like so (be aware that the standard prefixes are NOT supported out-of-the-box as with sopranocmd): | ||
<code cppqt> | <code cppqt="cppqt"> | ||
using namespace Soprano; | using namespace Soprano; | ||
Line 111: | Line 118: | ||
.arg(Node::literalToN3("foobar"))); | .arg(Node::literalToN3("foobar"))); | ||
</code> | </code> | ||
This will create the same query we used above only using no hard-coded components whatsoever. | This will create the same query we used above only using no hard-coded components whatsoever. | ||
== Restarting Nepomuk and its Services == | == Restarting Nepomuk and its Services == | ||
It is possible to stop the server and all services alltogether by simply calling a D-Bus method: | The Nepomuk services are controlled by the ''[[../NepomukServer|nepomukserver]]'' application which is started on KDE login. The nepomukserver will take care of starting and stopping all services. | ||
It is possible to stop the server and all services alltogether by simply calling a D-Bus method: | |||
<code> | <code> | ||
# qdbus org.kde.NepomukServer /nepomukserver \ | # qdbus org.kde.NepomukServer /nepomukserver \ | ||
org.kde.NepomukServer.quit | org.kde.NepomukServer.quit | ||
</code> | </code> | ||
It can then be restarted by simply calling ''nepomukserver'' again. In many debugging situations it might be of interest to pipe the output of the server (and all services) to a file: | It can then be restarted by simply calling ''nepomukserver'' again. In many debugging situations it might be of interest to pipe the output of the server (and all services) to a file: | ||
<code> | <code> | ||
# nepomukserver 2> /tmp/nepomuk.stderr | # nepomukserver 2> /tmp/nepomuk.stderr | ||
</code> | </code> | ||
Also interesting to know is that Nepomuk defines a set of debugging areas for the services and the server itself. Use ''kdebugdialog'' to enable or disable them. | Also interesting to know is that Nepomuk defines a set of debugging areas for the services and the server itself. Use ''kdebugdialog'' to enable or disable them. | ||
Or one can stop and start single services. In most cases this is sufficient since each service is run in its own process. Thus, changes to a service plugins will be picked up directly: | Or one can stop and start single services. In most cases this is sufficient since each service is run in its own process. Thus, changes to a service plugins will be picked up directly: | ||
<code> | <code> | ||
Line 141: | Line 149: | ||
# qdbus org.kde.NepomukServer /servicemanager \ | # qdbus org.kde.NepomukServer /servicemanager \ | ||
org.kde.nepomuk.ServiceManager.startService <servicename> | org.kde.nepomuk.ServiceManager.startService <servicename> | ||
</code> | </code> | ||
<br> | |||
== Listening to changes in the database == | == Listening to changes in the database == | ||
Nepomuk's database does only contain statements, i.e. quadruples. To date Soprano's Model does provide four signals which can be used to monitor new and removed statements: statementsAdded and statementsRemoved as well as their counterparts which have as paramter the added or removed statement. | Nepomuk's database does only contain statements, i.e. quadruples. To date Soprano's Model does provide four signals which can be used to monitor new and removed statements: statementsAdded and statementsRemoved as well as their counterparts which have as paramter the added or removed statement. | ||
It is recommended to use Soprano's [http://soprano.sourceforge.net/apidox/stable/classSoprano_1_1Util_1_1SignalCacheModel.html SignalCacheModel] when listening to changes to prevent a slowdown of the whole system as the signals are emitted for each statement: | It is recommended to use Soprano's [http://soprano.sourceforge.net/apidox/stable/classSoprano_1_1Util_1_1SignalCacheModel.html SignalCacheModel] when listening to changes to prevent a slowdown of the whole system as the signals are emitted for each statement: | ||
<code cppqt> | <code cppqt="cppqt"> | ||
Soprano::Util::SignalCacheModel* scm = new Soprano::Util::SignalCacheModel( | Soprano::Util::SignalCacheModel* scm = new Soprano::Util::SignalCacheModel( | ||
Nepomuk::ResourceManager::instance()->mainModel() ); | Nepomuk::ResourceManager::instance()->mainModel() ); | ||
Line 158: | Line 167: | ||
connect( scm, SIGNAL(statementsRemoved()), | connect( scm, SIGNAL(statementsRemoved()), | ||
this, SLOT(slotStatementsRemoved()) ); | this, SLOT(slotStatementsRemoved()) ); | ||
</code> | </code> | ||
== Remove all Strigi-indexed data == | == Remove all Strigi-indexed data == | ||
The little command below removes all data created by Strigi (caution: this could take a long time): | Strigi produces a lot of data in Nepomuk. There might be times where one wants to remove all that data manually. | ||
The little command below removes all data created by Strigi (caution: this could take a long time): | |||
<code> | <code> | ||
Line 169: | Line 179: | ||
?g <http://www.strigi.org/fields#indexGraphFor> ?r . }"`; | ?g <http://www.strigi.org/fields#indexGraphFor> ?r . }"`; | ||
do nepomukcmd rmgraph "$a"; done | do nepomukcmd rmgraph "$a"; done | ||
</code> | </code> | ||
''This only works with sopranocmd from Soprano >= 2.3.63!'' | |||
== Starting Nepomuk Sever from the Trunk in Ubuntu == | |||
Ubuntu currently does not package the Virtuoso library properly. It provides a package called ''virtuoso-nepomuk'' which installs the executable ''virtuoso-t'' in the ''/usr/lib/virtuoso/'' directory. | |||
When running Nepomuk from the trunk, the nepomukserver is unable to find the ''virtuoso-t'' executable, and therefore the NepomukStorage Service fails to initialize. One way to fix this is to copy the virtuoso-t binary from the ''/usr/lib/virtuoso/'' directory to either the ''/usr/bin'' directory (Bad! Requires root privileges) or the $KDEDIR/bin directory. |
Revision as of 14:25, 19 April 2010
Development/Tutorials/Metadata/Nepomuk/TipsAndTricks
Languages: عربي | Asturianu | Català | Česky | Kaszëbsczi | Dansk | Deutsch | English | Esperanto | Español | Eesti | فارسی | Suomi | Français | Galego | Italiano | 日本語 | 한국어 | Norwegian | Polski | Português Brasileiro | Română | Русский | Svenska | Slovenčina | Slovenščina | српски | Türkçe | Tiếng Việt | Українська | 简体中文 | 繁體中文
Tutorial Series | Nepomuk |
Previous | None |
What's Next | n/a |
Further Reading | Resource Handling with Nepomuk, |
Always initialize Nepomuk
Make sure that somewhere in the initialization code of your application or library Nepomuk is initialized via:
Nepomuk::ResourceManager::instance()->init();
Using ontology URIs in your code
One often needs the URI of a specific class or a specific property in ones code. And not all ontologies are provided by the very convenient Soprano::Vocabulary namespace.
The solution is rather simple: create your own vocbulary namespaces by using Soprano's own onto2vocabularyclass command line tool. It can generate convenient vocabulary namespaces for you. The Soprano documentation shows how to use it manually or even simpler with a simple CMake macro.
Mind the Difference between QString and QUrl
Nepomuk::Resource provides two constructors: one taking a QString as identifier or URI and one taking a QUrl.
The latter one is really simple: the given URI is used as the resource URI. If the resource exists, its data is used, otherwise it will be created with exactly that URI.
The QString one is a bit trickier. It will try to be clever about the parameter and see if it is a URI. If no resource with that URI (if it is a URI) exists, it is interpreted as an identifier (nao:identifier). Resource checks if a resource with that identifier exists. If so, its data is loaded, if not, a new resource with a random URI and that string as identifier is created.
However, be aware that nothing is written to Nepomuk until the first writing call to Resource such as setProperty or addType.
Debugging the created data
Using sopranocmd
When using Nepomuk one creates a lot of RDF statements in the Nepomuk RDF storage. It is often of interest to check which data has been created, if statements have been correctly created or simply look at existing data.
Soprano provides a nice command line client to do all this called sopranocmd. It provides all the features one needs to debug data: it can add and remove statements, list and query them, import and export whole RDF files, and even monitor for statementAdded and statementRemoved events.
To access the Nepomuk storage one would typically use the D-Bus interface:
- sopranocmd --dbus org.kde.NepomukStorage --model main <command> \
<parameters>
If one wanted to list all the resources that have been tagged with the tag whose resource URI is nepomuk:/foobar one would use the following command:
- sopranocmd --dbus org.kde.NepomukStorage --model main list \
"" "" "<nepomuk:/foobar>"
or one would use a SPARQL query (sopranocmd supports the standard URI prefixes out of the box):
- sopranocmd --dbus org.kde.NepomukStorage --model main query \
"select ?r where { ?r nao:hasTag ?tag . \
?tag nao:prefLabel 'foobar'^^xsd:string . }"
To monitor all statements that are added and removed from the Nepomuk storage one would simply use the following command (as with list one can specify a filter to only list the added and removed statements one is interested in):
- sopranocmd --dbus org.kde.NepomukStorage --model main monitor
# sopranocmd --help
is your friend for all details.
Hint: add the following to your .bashrc to avoid having to type in the dbus and model parameters all the time:
alias nepomukcmd="sopranocmd --socket ${HOME}/.kde/share/apps/nepomuk/socket --model main --nrl $@"
(Be aware that the --nrl parameter is only available in Soprano 2.3.63 and above.)
Using Konqueror
In the Nepomuk playground repository lives a KIO slave which can handle the nepomuk:/ protocol. It will display all properties of a Nepomuk resource including its links to other resources and the backlinks. This is a convenient way of looking at the Nepomuk data. The KIO slave even support removal of resources.
Using NepomukShell
The NepomukShell is another tool that lives in the playground. It is a simple tool that let's one browse all resources in Nepomuk. Additionally it allows to create subclasses and properties (Caution: do only create subclasses and properties from PIMO classes and properties!) and remove resources.
Constructing SPARQL queries
Hint: In most cases the Nepomuk Query API should be enough and prevent you from writing your own SPARQL which is hard to debug.
Whenever doing something a bit fancier with Nepomuk one has to use SPARQL queries via
Nepomuk::ResourceManager::instance()->mainModel()
->executeQuery( myQueryString,
Soprano::Query::QueryLanguageSparql );
Constructing these queries can be a bit cumbersome since one has to use a lot of class and property URIs from different ontologies. Also literals have to be formatted according to the N3 syntax used in SPARQL. Luckily Soprano provides the necessary tools to do exactly that: Soprano::Node::toN3, Soprano::Node::resourceToN3, and Soprano::Node::literalToN3 take care of all formatting and percent-encoding you need. Using those methods the code to create queries might look ugly but the resulting queries are more likely to be correctly encoded and introduce less code duplication.
Typically one would use QString::arg like so (be aware that the standard prefixes are NOT supported out-of-the-box as with sopranocmd):
using namespace Soprano;
QString myQuery
= QString("select ?r where { "
"?r %1 ?v . "
"?v %2 %3 . }")
.arg(Node::resourceToN3(Vocabulary::NAO::hasTag()))
.arg(Node::resourceToN3(Vocabulary::NAO::prefLabel()))
.arg(Node::literalToN3("foobar")));
This will create the same query we used above only using no hard-coded components whatsoever.
Restarting Nepomuk and its Services
The Nepomuk services are controlled by the nepomukserver application which is started on KDE login. The nepomukserver will take care of starting and stopping all services.
It is possible to stop the server and all services alltogether by simply calling a D-Bus method:
- qdbus org.kde.NepomukServer /nepomukserver \
org.kde.NepomukServer.quit
It can then be restarted by simply calling nepomukserver again. In many debugging situations it might be of interest to pipe the output of the server (and all services) to a file:
- nepomukserver 2> /tmp/nepomuk.stderr
Also interesting to know is that Nepomuk defines a set of debugging areas for the services and the server itself. Use kdebugdialog to enable or disable them.
Or one can stop and start single services. In most cases this is sufficient since each service is run in its own process. Thus, changes to a service plugins will be picked up directly:
- qdbus org.kde.NepomukServer /servicemanager \
org.kde.nepomuk.ServiceManager.stopService <servicename>
- qdbus org.kde.NepomukServer /servicemanager \
org.kde.nepomuk.ServiceManager.startService <servicename>
Listening to changes in the database
Nepomuk's database does only contain statements, i.e. quadruples. To date Soprano's Model does provide four signals which can be used to monitor new and removed statements: statementsAdded and statementsRemoved as well as their counterparts which have as paramter the added or removed statement.
It is recommended to use Soprano's SignalCacheModel when listening to changes to prevent a slowdown of the whole system as the signals are emitted for each statement:
Soprano::Util::SignalCacheModel* scm = new Soprano::Util::SignalCacheModel(
Nepomuk::ResourceManager::instance()->mainModel() );
connect( scm, SIGNAL(statementsAdded()),
this, SLOT(slotStatementsAdded()) );
connect( scm, SIGNAL(statementsRemoved()),
this, SLOT(slotStatementsRemoved()) );
Remove all Strigi-indexed data
Strigi produces a lot of data in Nepomuk. There might be times where one wants to remove all that data manually.
The little command below removes all data created by Strigi (caution: this could take a long time):
for a in `nepomukcmd --foo query "select distinct ?g where { \
?g <http://www.strigi.org/fields#indexGraphFor> ?r . }"`;
do nepomukcmd rmgraph "$a"; done
This only works with sopranocmd from Soprano >= 2.3.63!
Starting Nepomuk Sever from the Trunk in Ubuntu
Ubuntu currently does not package the Virtuoso library properly. It provides a package called virtuoso-nepomuk which installs the executable virtuoso-t in the /usr/lib/virtuoso/ directory.
When running Nepomuk from the trunk, the nepomukserver is unable to find the virtuoso-t executable, and therefore the NepomukStorage Service fails to initialize. One way to fix this is to copy the virtuoso-t binary from the /usr/lib/virtuoso/ directory to either the /usr/bin directory (Bad! Requires root privileges) or the $KDEDIR/bin directory.