Skip to content

Commit

Permalink
feat: collect search telemetry data
Browse files Browse the repository at this point in the history
  • Loading branch information
faustoq committed Jul 4, 2024
1 parent 7bf7609 commit a48c6f9
Show file tree
Hide file tree
Showing 8 changed files with 300 additions and 38 deletions.
106 changes: 95 additions & 11 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,118 @@
namespace OramaCloud;

use GuzzleHttp\Client as HttpClient;
use OramaCloud\Client\Cache;
use OramaCloud\Client\Query;
use OramaCloud\Manager\Endpoints;
use OramaCloud\Telemetry\Collector;

class Client
{
private $answersApiBaseURL;
private $apiKey;
private $endpoint;
private $http;
private $id;
private $collector;
private $cache = true;

public function __construct($endpoint, $apiKey, $answersApiBaseURL = null)
public function __construct(array $params)
{
$this->apiKey = $apiKey;
$this->endpoint = $endpoint;
$this->answersApiBaseURL = $answersApiBaseURL;
$params = $this->validate($params);

$this->id = uniqid('p', true);
$this->http = new HttpClient();
$this->apiKey = $params['api_key'];
$this->endpoint = $params['endpoint'];
$this->answersApiBaseURL = $params['answersApiBaseURL'];
$this->cache = $params['cache'];

// Telemetry is enabled by default
if ($params['telemetry'] !== false) {
$this->collector = Collector::create([
'id' => $this->id,
'api_key' => $this->apiKey,
'flushInterval' => $params['telemetry']['flushInterval'] ?? 5000,
'flushSize' => $params['telemetry']['flushSize'] ?? 25
]);
}

// Cache is enabled by default
if ($this->cache) {
$this->cache = new Cache();
}

$this->init();
}

public function search(Query $query)
{
$endpoint = "{$this->endpoint}/search?api-key={$this->apiKey}";
$cacheKey = "search-" . $query->toJson();

if ($this->cache && $this->cache->has($cacheKey)) {
$roundTripTime = 0;
$searchResults = $this->cache->get($cacheKey);
$cached = true;
} else {
$startTime = microtime(true);
$endpoint = "{$this->endpoint}/search?api-key={$this->apiKey}";
$response = $this->http->request('POST', $endpoint, [
'form_params' => [
'q' => $query->toJson()
]
]);

$searchResults = $response->getBody();

$response = $this->http->request('POST', $endpoint, [
'form_params' => [
'q' => $query->toJson()
]
]);
$endTime = microtime(true);
$roundTripTime = ($endTime - $startTime) * 1000;
$cached = false;

return json_decode($response->getBody(), true);
$this->cache->set($cacheKey, $searchResults);
}

if ($this->collector !== null) {
$this->collector->add([
'rawSearchString' => $query->toArray()['term'],
'resultsCount' => $searchResults->hits ?? 0,
'roundTripTime' => $roundTripTime,
'query' => $query->toJson(),
'cached' => $cached,
'searchedAt' => time()
]);
}

return json_decode($searchResults, true);
}

private function validate($params)
{
if (empty($params['api_key'])) {
throw new \InvalidArgumentException('API key is required');
}

if (empty($params['endpoint'])) {
throw new \InvalidArgumentException('Endpoint is required');
}

if (isset($params['telemetry']) && $params['telemetry'] !== false && !is_array($params['telemetry'])) {
throw new \InvalidArgumentException('Telemetry must be an array');
}

$params['telemetry'] = isset($params['telemetry']) ? $params['telemetry'] : [
'flushInterval' => 5000,
'flushSize' => 25
];

$params['answersApiBaseURL'] = isset($params['answersApiBaseURL']) ? $params['answersApiBaseURL'] : Endpoints::ORAMA_ANSWER_ENDPOINT;

$params['cache'] = isset($params['cache']) ? $params['cache'] : true;

return $params;
}

private function init()
{
//
}
}
77 changes: 77 additions & 0 deletions src/Client/Cache.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

namespace OramaCloud\Client;

class Cache
{
/**
* @var array The cache storage
*/
private $cache;

public function __construct()
{
$this->cache = [];
}

/**
* Set a value in the cache.
* @param string $key The key under which to store the value.
* @param mixed $value The value to store.
*/
public function set(string $key, $value): void
{
$this->cache[$key] = $value;
}

/**
* Get a value from the cache.
* @param string $key The key of the value to retrieve.
* @return mixed|null The value or null if not found.
*/
public function get(string $key)
{
return $this->cache[$key] ?? null;
}

/**
* Check if the cache has a key.
* @param string $key The key to check.
* @return bool True if the cache has the key, false otherwise.
*/
public function has(string $key): bool
{
return isset($this->cache[$key]);
}

/**
* Delete a value from the cache.
* @param string $key The key of the value to delete.
* @return bool True if the value was successfully deleted, false otherwise.
*/
public function delete(string $key): bool
{
if ($this->has($key)) {
unset($this->cache[$key]);
return true;
}
return false;
}

/**
* Clear the cache.
*/
public function clear(): void
{
$this->cache = [];
}

/**
* Get the size of the cache.
* @return int The number of items in the cache.
*/
public function size(): int
{
return count($this->cache);
}
}
39 changes: 24 additions & 15 deletions src/Query.php → src/Client/Query.php
Original file line number Diff line number Diff line change
@@ -1,48 +1,55 @@
<?php

namespace OramaCloud;
namespace OramaCloud\Client;

use OramaCloud\QueryParams\Where;

class Query {
use OramaCloud\Client\QueryParams\Where;

class Query
{
private $term;
private $mode;
private $limit;
private $offset;
private $where = [];

public function __construct($term = '', $mode = 'fulltext') {
public function __construct($term = '', $mode = 'fulltext')
{
$this->term = $term;
$this->mode = $mode;
}

public function term($term) {
public function term($term)
{
$this->term = $term;
return $this;
}

public function mode($mode) {
public function mode($mode)
{
$this->mode = $mode;
return $this;
}

public function where($property, $operator, $value) {
public function where($property, $operator, $value)
{
$this->where[] = new Where($property, $operator, $value);
return $this;
}

public function limit($limit) {
public function limit($limit)
{
$this->limit = $limit;
return $this;
}

public function offset($offset) {
public function offset($offset)
{
$this->offset = $offset;
return $this;
}

public function toArray() {
public function toArray()
{
$array = [];

if (!is_null($this->term)) {
Expand Down Expand Up @@ -72,16 +79,18 @@ public function toArray() {
return $array;
}

public function toJson() {
public function toJson()
{
return json_encode($this->toArray());
}

public static function fromArray($array) {
public static function fromArray($array)
{
$query = new Query();

$query->term(isset($array['term']) ? $array['term'] : '');
$query->mode(isset($array['mode']) ? $array['mode'] : 'fulltext');

if (isset($array['where']) && !is_null($array['where'])) {
foreach ($array['where'] as $property => $value) {
$query->where($property, key($value), $value[key($value)]);
Expand Down
13 changes: 8 additions & 5 deletions src/QueryParams/Where.php → src/Client/QueryParams/Where.php
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
<?php

namespace OramaCloud\QueryParams;
namespace OramaCloud\Client\QueryParams;

class Where {
class Where
{

private $property;
private $operator;
private $value;

public function __construct($property, $operator, $value) {

public function __construct($property, $operator, $value)
{
$this->property = $property;
$this->operator = $operator;
$this->value = $value;
}

public function toArray() {
public function toArray()
{
return [
$this->property => [
$this->operator => $this->value
Expand Down
2 changes: 2 additions & 0 deletions src/Manager/Endpoints.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ class Endpoints
const NOTIFY = self::WEBHOOKS_BASE_URL . '/[indexID]/notify';

const SNAPSHOT = self::WEBHOOKS_BASE_URL . '/[indexID]/snapshot';

const ORAMA_ANSWER_ENDPOINT = 'https://answer.api.orama.com';
}
Loading

0 comments on commit a48c6f9

Please sign in to comment.