2

I'm working on multi user web application in Flask. Till yet I used MySQL as data source. Now, I'm adding some functionality that would require Prolog as inference engine. My question is related to way, how to handle fact and rules data. I don't think it is good option to create on each web request Prolog file from MySQL data a consult this new created file on server. Prolog data should be somehow persisted on server and Prolog engine update after addition of some fact or rule. Has anybody encountered this before? What is correct way of implementation of this kind of functionality?

So please, how to persist Prolog data in multiuser web application, where each user can add some facts or even rules. And other users should immediately see changed data. How to to it robust and proper way?

  • 2
    This is not a duplicate of the linked question, which is a solution in the Python domain. This problem is in the Prolog domain of your program, you need a way to persist changes in the Prolog. As you're in SWI-Prolog, library persistency is your best bet. If you need help and they won't remove the duplicate tag, ask again but only tag with Prolog... – Paul Brown Sep 01 '19 at 18:48
  • I'd consider keeping it in the database and access it from Prolog using [library(odbc)](https://www.swi-prolog.org/pldoc/doc_for?object=section(%27packages/odbc.html%27)). – Daniel Lyons Sep 03 '19 at 14:25

1 Answers1

3

This is a big and complicated question. Let's start breaking it down.

In the SWI-Prolog side you need a dynamic but persistent database. Here library(persistency) will handle this for you.

But, and it's a big but, Flask is a multi-threaded application, meaning you need some way to communicate with SWI-Prolog in a multi-threaded way and your data updates also need to be thread safe. PySWIP can't handle this.

For the SWI-Prolog you'll need to wrap all of your library(persistency) predicates in a with_mutex/2 for thread safety.

The best bet for multi-threaded communication with SWI-Prolog is via pengines. In this way you run your SWI-Prolog in its own server and communicate with it via HTTP requests. The library(persistency) predicates use a mutex, so are considered unsafe, which means you'll have to mark them as safe.

There is a pip install pengines, but the docs are out of sync with the development. You don't need to call pengine.create(), but you will need to call pengine.doAsk(query) after query = pengine.ask() and finish a set of queries with pengine.iAmFinished(query). It's not a bad idea to read the source code on this one.

It can all be clobbered together and it does work!

Paul Brown
  • 2,235
  • 12
  • 18
  • Seen as it's so complicated, here's a template: https://github.com/PaulBrownMagic/blog_notebooks/tree/master/flask_prolog I'll write it up in a blog post, when I get a bit of time for it! – Paul Brown Sep 02 '19 at 18:30
  • You might also consider if it's worth porting the whole application across to SWI-Prolog. Here's a SWI Web Dev tutorial: http://www.pathwayslms.com/swipltuts/html/index.html#_sessions, you might find the simple-template mentioned more familiar than termerized html. – Paul Brown Sep 02 '19 at 18:37
  • Do you think you could extend your github project for example of addition of some rule? Because I would need to dynamically add some rules with various rule definition and various number of parameters. Thanks. – Peter Boško Sep 07 '19 at 10:34
  • This works. However it takes approximately 2.2 sec on my computer to add one word. What could be a problem in production environment with more users and bigger facts and rules vocabularies. But I think I can live with it for now. – Peter Boško Sep 07 '19 at 16:33
  • That's strange, on my machine it's taking between 0.003 and 0.005 seconds to do a call like `greetings.add_adjective(word)`. Whilst possible to add rules to be persisted and called in SWI-Prolog, I can't recommend it. You'd be bypassing the sandbox: the code has access to the underlying OS. It would take pengine expertise to make this secure. Instead I recommend you store these rules as strings in Python and send them with the query that requires them, thus they'll be sandboxed. `srctext` is a kwarg for `PengineBuilder` instantiation. – Paul Brown Sep 07 '19 at 20:03