Nilesh has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/72116


Change subject: Added prototype PHP client
......................................................................

Added prototype PHP client

Change-Id: Iefd1996468a684be57aabde18faffa114b08f9df
---
A php-client/README.md
A php-client/composer.json
A php-client/src/WesPHPClient/EntitySuggesterService.php
A php-client/src/WesPHPClient/MyrrixClient.php
A php-client/src/WesPHPClient/service.json
A php-client/wesTest.php
6 files changed, 474 insertions(+), 0 deletions(-)


  git pull 
ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/WikidataEntitySuggester 
refs/changes/16/72116/1

diff --git a/php-client/README.md b/php-client/README.md
new file mode 100644
index 0000000..f3b0a2b
--- /dev/null
+++ b/php-client/README.md
@@ -0,0 +1,79 @@
+# Wikidata Entity Suggester PHP Client
+
+This is the PHP client for the [Wikidata Entity 
Suggester](https://github.com/nilesh-c/wikidata-entity-suggester). It uses the 
Entity Suggester's REST API to push data and get suggestions.
+
+## Installation via Composer
+
+The best way to use the library is via [Composer](http://getcomposer.org/).
+
+After you install composer, run in console:
+
+```
+cd your/working/directory
+composer require guzzle/guzzle
+composer require wes-php-client/wes-php-client
+```
+
+Type 'dev-master' for both, when prompted for the version.
+
+OR
+
+You can manually add the library to your dependencies in the composer.json 
file:
+
+```
+{
+    "require": {
+        "wes-php-client/wes-php-client": "dev-master"
+    }
+}
+```
+
+and install your dependencies:
+
+```
+composer install
+```
+
+## Usage
+
+``` php
+// Always include this file to use the client
+require_once("vendor/autoload.php");
+
+// Instanciate the Myrrix/Entity Suggester service
+$wes = new EntitySuggesterService('localhost', 8080);
+
+// Push the data in the file /path/data.csv into the Entity Suggester.
+// Please check [this 
page](https://github.com/nilesh-c/wikidata-entity-suggester/wiki/CSV-file-explanation)
 for info on how the data should be structured in the CSV file.
+$wes->ingestFile("/path/data.csv");
+
+// Refresh the index (add newly added data into the model)
+$wes->refresh();
+
+// Get value recommendations for a new item
+$recommendation = $myrrix->getRecommendation(array(
+                                                    "107----4167410",
+                                                    "106",
+                                                    "107----215627",
+                                                    "156"
+                                                ), "value"); // returns an 
array of property-value pairs and strengths (example: 
[["107----4167410",0.53],["373----Huntsville  Alabama",0.499]])
+
+// Get property recommendations for a new item
+$recommendation = $myrrix->getRecommendation(array(
+                                                    "107----4167410",
+                                                    "106",
+                                                    "107----215627",
+                                                    "156"
+                                                ), "property"); // returns an 
array of properties and strengths (example: [["25",0.53],["156",0.499]])
+
+// Specify the number of recommendations (optional)
+$recommendation = $myrrix->getRecommendation(array(
+                                                    "107----4167410",
+                                                    "106",
+                                                    "107----215627",
+                                                    "156"
+                                                ), "property", 20); // returns 
an array of 20 properties with strengths (example: [["25",0.53],["156",0.499]])
+
+```
+
+See [wesTest.php](wesTest.php) for a crude example/demo. It is temporarily 
deployed [here](http://173.0.50.123/wesTest.php).
diff --git a/php-client/composer.json b/php-client/composer.json
new file mode 100644
index 0000000..606cad1
--- /dev/null
+++ b/php-client/composer.json
@@ -0,0 +1,23 @@
+{
+    "name": "wes-php-client/wes-php-client",
+    "description": "PHP Client for Wikidata Entity Suggester",
+    "type": "library",
+    "keywords": ["wikidata", "entity-suggester", "myrrix", "recommendation"],
+    "homepage": "https://github.com/nilesh-c/wes-php-client";,
+    "license": "MIT",
+    "stability": "dev",
+    "minimum-stability": "dev",
+    "autoload": {
+        "psr-0": { "WesPHPClient": "src/" }
+    },
+    "require": {
+        "guzzle/guzzle": "dev-master"
+    },
+    "authors": [
+        {
+            "name": "Nilesh Chakraborty",
+            "email": "[email protected]",
+            "homepage": "http://nileshc.com";
+        }
+    ]
+}
diff --git a/php-client/src/WesPHPClient/EntitySuggesterService.php 
b/php-client/src/WesPHPClient/EntitySuggesterService.php
new file mode 100644
index 0000000..c098237
--- /dev/null
+++ b/php-client/src/WesPHPClient/EntitySuggesterService.php
@@ -0,0 +1,120 @@
+<?php
+
+namespace WesPHPClient;
+
+/**
+ * EntitySuggesterService helps you leverage the Entity Suggester REST api
+ */
+class EntitySuggesterService {
+
+    /**
+     * @var MyrrixClient
+     */
+    protected $client;
+
+    /**
+     * @param string $host     The hostname
+     * @param int    $port     The port
+     * @param string $username The username
+     * @param string $password The password
+     */
+    function __construct($host, $port, $username = null, $password = null) {
+        $this->client = MyrrixClient::factory(array(
+                    'hostname' => $host,
+                    'port' => $port,
+                    'username' => $username,
+                    'password' => $password,
+                ));
+    }
+
+    /**
+     * Gets a recommendation for an unknown item, infer its recommended 
properties/values using a preference(list of properties and property-values) 
array.
+     *
+     * @param array $properties The known properties of the unknown item
+     * @param int   $count       The number of results to retrieve
+     *
+     * @return array
+     */
+    public function getRecommendation(array $properties = array(), $type = 
"property", $count = null) {
+        $command = $this->client->getCommand('GetRecommendation', array(
+            'properties' => $properties,
+            'type'=>$type,
+            'howMany' => $count,
+                ));
+
+        return $this->client->execute($command)->json();
+    }
+
+    /**
+     * Sets a list of item-property or item-property+value pairs
+     *
+     * @param array $properties An array of arrays with keys 'userID', 
'itemID' and 'value'
+     *
+     * @return bool
+     */
+    public function ingest(array $properties) {
+        $command = $this->client->getCommand('Ingest', array(
+            'data' => $properties,
+                ));
+
+        return $this->client->execute($command)->isSuccessful();
+    }
+
+    /**
+     * Sets a list of item-property or item-property+value pairs from a CSV 
file
+     *
+     * @param string $fileName The path/filename of the csv file with 
<item>,<property/value>,<strength value> entries
+     *
+     * @return bool
+     */
+    public function ingestFile(string $fileName) {
+        $f = fopen($fileName, "r");
+        $ingestFeed = array();
+        if($f === false)
+            throw new Exception("Sorry, cannot open file $fileName");
+        while(!feof($f)) {
+            $prefs = trim(fgets($f));
+            if(empty($prefs)) {
+                continue;
+            } else {
+                $prefs = explode(",", $prefs);
+            }
+            $ingestFeed[] = array(
+                                'userID'=>$prefs[0],
+                                'itemID'=>$prefs[1],
+                                'value'=>$prefs[2]
+                                );
+        }
+        return $this->ingest($ingestFeed);
+    }
+
+    /**
+     * Asks Myrrix to refresh, may take time.
+     *
+     * @return bool
+     */
+    public function refresh() {
+        $command = $this->client->getCommand('Refresh');
+
+        return $this->client->execute($command)->isSuccessful();
+    }
+
+    /**
+     * Asks if Myrrix is ready to answer requests.
+     *
+     * @return bool
+     */
+    public function isReady() {
+        $command = $this->client->getCommand('Ready');
+
+        return $this->client->execute($command)->isSuccessful();
+    }
+
+    /**
+     * @return MyrrixClient
+     */
+    public function getClient() {
+        return $this->client;
+    }
+
+}
diff --git a/php-client/src/WesPHPClient/MyrrixClient.php 
b/php-client/src/WesPHPClient/MyrrixClient.php
new file mode 100644
index 0000000..1f4cc4b
--- /dev/null
+++ b/php-client/src/WesPHPClient/MyrrixClient.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace WesPHPClient;
+
+use Guzzle\Service\Client;
+use Guzzle\Common\Collection;
+use Guzzle\Service\Description\ServiceDescription;
+use Guzzle\Parser\ParserRegistry;
+use Guzzle\Plugin\CurlAuth\CurlAuthPlugin;
+
+class MyrrixClient extends Client {
+
+    public static function factory($config = array()) {
+        $default = array(
+            'base_url' => 'http://{hostname}:{port}',
+            'hostname' => 'localhost',
+            'port' => 8080,
+            'username' => null,
+            'password' => null,
+        );
+        $required = array('hostname', 'port', 'base_url', 'username', 
'password');
+        $config = Collection::fromConfig($config, $default, $required);
+
+        $client = new self($config->get('base_url'), $config);
+        $client->setDescription(ServiceDescription::factory(__DIR__ . 
DIRECTORY_SEPARATOR . 'service.json'));
+
+        $client->setDefaultHeaders(array(
+            'Accept' => 'text/html',
+        ));
+
+        $authPlugin = new CurlAuthPlugin($config['username'], 
$config['password']);
+        $client->addSubscriber($authPlugin);
+
+        return $client;
+    }
+
+    public static function filterIngestData(array $data) {
+        $result = '';
+
+        foreach ($data as $line) {
+            $result .= $line['userID'] . ',' . $line['itemID'] . 
(isset($line['value']) ? ',' . $line['value'] : '') . PHP_EOL;
+        }
+
+        return $result;
+    }
+
+}
diff --git a/php-client/src/WesPHPClient/service.json 
b/php-client/src/WesPHPClient/service.json
new file mode 100644
index 0000000..6556991
--- /dev/null
+++ b/php-client/src/WesPHPClient/service.json
@@ -0,0 +1,79 @@
+{
+    "name": "Wikidata Entity Suggester",
+    "apiVersion": "2012-12-15",
+    "description": "Wikidata Entity Suggester is a recommendation engine for 
wikidata that can suggest properties or values to a newly created or not yet 
created item",
+    "operations": {
+        "GetRecommendation": {
+            "httpMethod": "GET",
+            "uri": "/entitysuggester/suggest{/properties*}?type={type}",
+            "summary": "Gets a recommendation for an anonymous item",
+            "parameters": {
+                "properties": {
+                    "location": "uri",
+                    "description": "The properties and property-value pairs 
that the item has. Keys are the items, values are the strengths of the 
associations.",
+                    "required": true,
+                    "type": "array",
+                    "items": {
+                        "description": "A value describing the strength of the 
observed association.",
+                        "type": "string"
+                    }
+                },
+                "type": {
+                    "location": "uri",
+                    "description": "Type of recommendation - property or 
value.",
+                    "required": true,
+                    "type": "string"
+                },
+                "howMany": {
+                    "location": "query",
+                    "description": "Maximum number of recommendations to 
return.",
+                    "type": "integer"
+                }
+            }
+        },
+        "Ingest": {
+            "httpMethod": "POST",
+            "uri": "/entitysuggester/ingest",
+            "summary": "Supports bulk-loading new properties.",
+            "parameters": {
+                "data": {
+                    "description": "New properties",
+                    "required": true,
+                    "location": "body",
+                    "type": "array",
+                    "minItems": 1,
+                    "filters": 
["WesPHPClient\\MyrrixClient::filterIngestData"],
+                    "items": {
+                        "type": "object",
+                        "properties": {
+                            "userID": {
+                                "type": "string",
+                                "description": "The user ID",
+                                "required": true
+                            },
+                            "itemID": {
+                                "type": "string",
+                                "description": "The item ID",
+                                "required": true
+                            },
+                            "value": {
+                                "description": "A value describing the 
strength of the observed association.",
+                                "type": "numeric"
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "Ready": {
+            "httpMethod": "HEAD",
+            "uri": "/ready",
+            "summary": "Tells whether the Serving Layer is ready to answer 
requests -- has loaded or computed a model."
+        },
+        "Refresh": {
+            "httpMethod": "POST",
+            "uri": "/refresh",
+            "summary": "Requests that the recommender rebuild its internal 
state and models."
+        }
+    }
+}
diff --git a/php-client/wesTest.php b/php-client/wesTest.php
new file mode 100644
index 0000000..6f74ff6
--- /dev/null
+++ b/php-client/wesTest.php
@@ -0,0 +1,126 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Testing PHP client for Wikidata Entity Suggester</title>
+    </head>
+    <body>
+<?php
+require_once("vendor/autoload.php");
+
+use WesPHPClient\EntitySuggesterService;
+
+if (!isset($_POST['data'])) {
+    ?>
+    <h1>Enter data</h1>
+    <form action="wesTest.php" method="post">
+        Please enter the properties and property----value pairs in this text 
box. An example set is already given.<br/><br/>
+        <textarea rows="10" cols="50" name="data">
+107----4167410
+106
+107----215627
+156
+        </textarea><br/><br/>
+        <input type="radio" name="t" value="value" checked>Suggest values
+        <input type="radio" name="t" value="property">Suggest properties
+        <br/><br/>
+        <input type="submit" value="Get suggestions!"/>
+    </form>
+
+    <?php
+    exit;
+}
+$wes = new EntitySuggesterService('127.0.0.1', 8080);
+$type = isset($_POST['t']) ? $_POST['t'] : "property";
+if (trim($_POST['data']) == '')
+    die("You must provide some data.");
+$data = array_map('trim', explode("\n", str_replace(" ", "", $_POST['data'])));
+
+$results = $wes->getRecommendation($data, $type, 10);
+
+mysql_connect("localhost", "root", "hackalot");
+mysql_select_db("wikidatawiki") or die(mysql_error());
+
+if ($type == "property") {
+    echo "<h1>Suggested properties:</h1><br/>\n";
+    $query = "SELECT pl_id, pl_text FROM plabel WHERE pl_lang='en' AND pl_id 
IN (";
+    ?>
+    <table border="1">
+        <tr>
+            <th>PropertyID</th>
+            <th>Property Value</th>
+        </tr>
+    <?php
+    foreach ($results as $result) {
+        $query .= "$result[0],";
+    }
+    $query = substr($query, 0, -1) . ")";
+    $mysqlResult = mysql_query($query) or die(mysql_error());
+    while ($fetch = mysql_fetch_assoc($mysqlResult)) {
+        ?>
+            <tr>
+                <td><?php echo $fetch['pl_id']; ?></td>
+                <td><?php echo $fetch['pl_text']; ?></td>
+            </tr>
+        <?php
+    }
+} else {
+    echo "<h1>Suggested property-value pairs:</h1><br/>\n";
+    ?>
+        <table border="1">
+            <tr>
+                <th>PropertyID</th>
+                <th>Property</th>
+                <th>ValueID</th>
+                <th>Value</th>
+            </tr>
+    <?php
+    $map = array();
+    $query = "SELECT pl_id, pl_text FROM plabel WHERE pl_lang='en' AND pl_id 
IN (";
+    foreach ($results as $result) {
+        $result = explode("----", $result[0]);
+        $query .= $result[0] . ",";
+    }
+    $query = substr($query, 0, -1) . ")";
+    $mysqlResult = mysql_query($query) or die(mysql_error());
+    while ($fetch = mysql_fetch_assoc($mysqlResult)) {
+        $map[$fetch['pl_id']] = $fetch['pl_text'];
+    }
+
+    $query = "SELECT l_id, l_text FROM label WHERE l_lang='en' AND l_id=";
+    foreach ($results as $result) {
+        $result = explode("----", $result[0]);
+        if (!isset($result[1])) {
+            continue;
+        } else {
+            if (is_numeric($result[1])) {
+                $mysqlResult = mysql_query($query . $result[1]) or 
die(mysql_error());
+                while ($fetch = mysql_fetch_assoc($mysqlResult)) {
+                    $valID = $fetch['l_id'];
+                    $valText = $fetch['l_text'];
+                }
+                ?>
+                        <tr>
+                            <td><?php echo $result[0]; ?></td>
+                            <td><?php echo $map[$result[0]]; ?></td>
+                            <td><?php echo $valID; ?></td>
+                            <td><?php echo $valText; ?></td>
+                        </tr>
+                <?php
+            } else {
+                ?>
+                        <tr>
+                            <td><?php echo $result[0]; ?></td>
+                            <td><?php echo $map[$result[0]]; ?></td>
+                            <td></td>
+                            <td><?php echo $result[1]; ?></td>
+                        </tr>
+                <?php
+            }
+        }
+    }
+}
+flush();
+?>
+        <a href="wesTest.php"> Go Back </a>
+        </body>
+        </html>
\ No newline at end of file

-- 
To view, visit https://gerrit.wikimedia.org/r/72116
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Iefd1996468a684be57aabde18faffa114b08f9df
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/WikidataEntitySuggester
Gerrit-Branch: master
Gerrit-Owner: Nilesh <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to