Percolator Agnostic Microservice


(Michael Palmer) #1

So, my problem currently is I am trying to create a microservice to act as a Percolate Proxy. The intent is that this microservice will use Elasticsearch as it's only backend, and will be responsible for creating indexes and registering percolators based on an index name and a JSON context passed in, populate the index based on an index name and queries (or JSON of queries) passed in, percolate a document based on an index name and a document passed in, and finally unregister and delete a percolator and index based on an index name passed in.

My problem so far is this: There is no good, in-depth documentation on the Percolate functionality in NEST. I am not sure if this is the right place to be asking for help, but I'm trying to figure out the problem however I can. I have been able to easily create and use Percolate via Marvel using Sense without a problem, but then figuring out how to use raw JSON to create an index in NEST (done, not too difficult), and then register it (this is the part that is stumping me) has me at a stand-still.

Does anyone know of some good documentation on this, or has anyone else done something like this? If not, I am going to keep working away at it and will try to post whatever ends up working here for future documentation if people think it would be worthwhile. Thanks for any assistance.

For some more direction as to what I am trying:
Currently, I create an index without a problem. Then, I try to create a RegisterPercolatorRequest object but I only have an index Actual Name (and alias to be applied later). So I create the RegisterPercolatorRequest as such:

var test = new RegisterPercolatorRequest(new IndexNameMarker { Name = index.ActualName }, index.ActualName);
var percolateResponse = client.RegisterPercolator(test);

In the percolateResponse object, I am getting the following error message:

[indexName_635684041078375596] failed to parse query [indexName_635684041078375596]

This is probably because the RegisterPercolatorRequest doesn't have a QueryContainer, but I have been unable to figure out how to create a valid query container from a JSON string... If I could do that, I think that would at least move me to the next step in the process...

The Index Object being sent in is this:

Name = 'monkeytest', 
Context = '{"banana":"color","breed":"string","country":"someplace","color":"color","height":10.5,"weight":20.5}', 
Queries = '{"name":"likesgreenbananas","context":{"query":{"match":{"banana":"green"}}}}'

NOTE on the above object, the intent is to eventually replace the single JSON String Query with multiple queries to populate the Percolator with

My whole Percolate class so far looks like this:

public class Index : DomainEntity<Index>
{
    public string Name { get; set; }
    public string ActualName { get; set; }
    public string Context { get; set; }
    public IEnumerable<string> Queries { get; set; }
}

// NOTE: The Client is made available via dependency injection.  It is functioning here, and DOES create the index successfully.
public bool CreateIndex(Models.Index index)
    {
        var success = false;

        SynchClusterSettings(client, logger);  // This just verifies and updates cluster settings

        foreach (
            var ind in
                client.GetAliases(a => a)
                    .Indices.Where(i => i.Key.StartsWith(index.Name + "_"))
                    .Where(i => i.Value.All(a => a.Name != index.Name))
                    .Select(kvp => kvp.Key))
        {
            var i = ind;
            // logger.Log(string.Format("...deleting index {0}o", i));
            client.DeleteIndex(s => s.Index(i));
        }

        var alias = client.GetAlias(a => a.Alias(index.Name));

        index.ActualName = string.Format("{0}_{1}", index.Name, DateTime.Now.Ticks);

        var bulkTasks = new List<Task<IBulkResponse>>();

        var indexResponse = client.Raw.IndicesCreatePost(index.ActualName, index.Context);

        if (!indexResponse.Success || indexResponse.HttpStatusCode != 200) {
            throw new ElasticsearchServerException(indexResponse.ServerError);
        }

// NOTE: This is where I start running into the issues with this
        var test = new RegisterPercolatorRequest(new IndexNameMarker { Name = index.ActualName }, index.ActualName);
                    
        var percolateResponse = client.RegisterPercolator(test);
        
        // NOTE: This portion works fine when I comment out the RegisterPercolate
        if (index.Queries != null & indexResponse.Success)
        {
            success = PopulateIndex(index);
        }
        else if (indexResponse.Success ) success = true;

        //Make sure alias is on correct index
        if (alias.Indices.Count == 0)
        {
            //Only need to add the new alias
            if (!client.Alias(a => a.Add(add => add.Index(index.ActualName).Alias(index.Name))).IsValid)
            {
                throw new Exception(string.Format("Unable to add alias {1} for index {0}", index.ActualName, index.Name));
            }
        }
        else
        {
            //Shouldn't be more than one, but if there is, delete all but one
            if (alias.Indices.Count > 1)
            {
                foreach (var i in alias.Indices.Take(alias.Indices.Count - 1))
                {
                    if (!client.Alias(a => a.Remove(remove => remove.Index(i.Key).Alias(index.Name))).IsValid)
                    {
                        throw new Exception(string.Format("Unable to remove alias {1} for index {0}", i.Key, index.Name));
                    };
                }
                //Refresh list
                alias = client.GetAlias(a => a.Alias(index.Name));
            }

            //Need to first remove the existing one, then add the new alias, all in one request
            if (
                !client.Alias(
                    a =>
                        a.Remove(remove => remove.Index(alias.Indices.Keys.Single()).Alias(index.Name))
                            .Add(add => add.Index(index.ActualName).Alias(index.Name))).IsValid)
            {
                throw new Exception(string.Format("Unable to remove and add alias {1} for index {0}", index.ActualName, index.Name));
            }

            //Delete old index
            foreach (
                var ind in
                    client.GetAliases(a => a)
                        .Indices.Where(i => i.Key.StartsWith(index.Name + "_"))
                        .Where(i => i.Value.All(a => a.Name != index.Name))
                        .Select(kvp => kvp.Key))
            {
                var i = ind;
                // logger.Log(string.Format("Deleting old index {0}", i));
                client.DeleteIndex(s => s.Index(i));
            }

        }
        return success;
    }

(system) #2