Autocomplete filtration depending on permission

103 views Asked by At

i want to filter the suggestions of cognitive search depending on the permissions. all items in the index have like this object

 "permissions": {
        "readitem": ";[email protected];;[email protected];;[email protected];",
        "readlist": ";[email protected];;[email protected];;[email protected];"
    },

If the email of the user is one of the emails in the readitem, then he is allowed to see only the suggestions of the items that have his email.

i'm trying to use search.ismatch("[email protected]|[email protected]|[email protected]",permissions/readitem) like that

            SuggestOptions sp = new SuggestOptions()
        {
            UseFuzzyMatching = query.Fuzzy,
            Size = 10,
            Filter = "search.ismatch(\"[email protected]|[email protected]|[email protected]\",permissions/readitem)",
        };

but search.ismatch is only supported in the Search API and I have tried to use odata-filter-expr but it works only with arrays.

Any way to overcome this?

2

There are 2 answers

0
M.bo.yazan On BEST ANSWER

I solved this issue by creating an output field like this.

cosmosDbIndexer.OutputFieldMappings.Add(new FieldMapping("/permissions/readitem") { TargetFieldName = "hasPermission" });

and I used the rest of the API of cognitive search to select the retrieved items. Everything is described in the Microsoft document.  https://learn.microsoft.com/en-us/rest/api/searchservice/autocomplete

here is the Request:

POST https://[service name].search.windows.net/indexes/[index name]/docs/autocomplete?api-version=[api-version]
      Content-Type: application/json   
      api-key: [admin or query key]

Body:
{  
  "autocompleteMode": "oneTerm" (default) | "twoTerms" | "oneTermWithContext",
   "fuzzy": true | false (default),  
  "highlightPreTag": "pre_tag",  
  "highlightPostTag": "post_tag",  
  "minimumCoverage": # (% of index that must be covered to declare query 
       successful; default 80),
  "search": "partial_search_input",  
  "searchFields": "title, hasPermission, ...",
  "suggesterName": "suggester_name",  
  "top": # (default 5)  
}

The response is handled like that.

string[] groups= ["[email protected]","[email protected]","[email protected]"];
IEnumerable<string> suggestions = response.value.Where(x => HasPermission(x.HasPermission, groups)).Select(x => x.Title);
0
Suresh Chikkam On

Create a field in your index that contains the principal identifiers. This field should be a string with the “filterable” attribute, and it should be a collection that doesn’t allow nulls.

In the above question The search.in function typically works with arrays, not delimited strings. Since your permissions field is a delimited string, you might encounter issues with this approach.

  • Below is the code which I used to filter suggestions based on user permissions in this scenario, you'll need to use a combination of string manipulation and LINQ.
using Microsoft.Azure.Search;
using Microsoft.Azure.Search.Models;
using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        // Replace with your Azure Cognitive Search service and index information
        string searchServiceName = "your-search-service-name";
        string queryApiKey = "your-query-api-key";
        string indexName = "your-index-name";

        SearchServiceClient serviceClient = new SearchServiceClient(searchServiceName, new SearchCredentials(queryApiKey));
        ISearchIndexClient indexClient = serviceClient.Indexes.GetClient(indexName);

        // Define the user's email
        string userEmail = "[email protected]";

        // Define the original suggestion query
        SuggestParameters suggestParameters = new SuggestParameters
        {
            UseFuzzyMatching = true,  // Adjust as needed
            Size = 10,  // Adjust as needed
        };

        // Execute the original suggestion query
        DocumentSuggestResult response = indexClient.Documents.Suggest("your-suggestion-text", "your-suggester-name", suggestParameters);

        // Filter the suggestions based on user permissions
        List<SuggestResult> filteredSuggestions = response.Results
            .Where(result => HasPermission(userEmail, result.Document["permissions"].ToString()))
            .ToList();

        // Now, 'filteredSuggestions' contains only the suggestions that match the user's permissions
    }

    // Function to check if the user's email is in the delimited permissions string
    static bool HasPermission(string userEmail, string permissions)
    {
        if (string.IsNullOrWhiteSpace(permissions))
        {
            return false;
        }

        // Remove leading and trailing semicolons
        permissions = permissions.Trim(';');

        // Split the delimited string into an array of emails
        string[] permissionEmails = permissions.Split(new[] { ";;" }, StringSplitOptions.None);

        // Check if the user's email is in the array
        return permissionEmails.Contains(userEmail);
    }
}
  • HasPermission function, which checks if the user's email is in the delimited permissions string.

Sample data in index:

[
    {
        "id": "1",
        "suggestion_text": "Suggestion 1",
        "permissions": {
            "readitem": ";[email protected];;[email protected];;[email protected];"
        }
    },
    {
        "id": "2",
        "suggestion_text": "Suggestion 2",
        "permissions": {
            "readitem": ";[email protected];;[email protected];;[email protected];"
        }
    },
    {
        "id": "3",
        "suggestion_text": "Suggestion 3",
        "permissions": {
            "readitem": ";[email protected];;[email protected];;[email protected];"
        }
    }
]

filteredSuggestions list: enter image description here

The user with the email "[email protected]" can only see suggestions 1 and 3 because their email is included in the readitem permission field of those suggestions.