How to get isFeatureEnabled to return the same value for all users in the same organization? - optimizely

Let's say I have a small business product that we are selling to organizations. How do I ensure that all users in the same organization get the same experience?
For example, let's say I have the following two users (user with id 123 and user with id 456) who belong to the same organization (organization with id 789).
Calling isFeatureEnabled('my_feature', userId) returns different values for the different users.
How do I ensure that user 123 and 456 get the same experience since they belong to the same organization?

There are a few ways you can do this depending on the use case. The full API signature of isFeatureEnabled is the following:
isFeatureEnabled(feature_key, userId, attributes)
where in general:
isFeatureEnabled(
'my_feature', // feature key identifier linking feature to Optimizely UI
'123', // userId parameter used as input to random bucketing
{ 'organizationId': '789' } // attributes used for non-random targeting
)
--
Use Case 1: If you want to manually select one-by-one which organization gets the feature enabled, you should use audience targeting via attributes.
You can pass in the organizationId as an attribute and setup an audience to target all visitors that are in that organization.
isFeatureEnabled('my_feature', '123', { organizationId: '789' } ); // User 123
isFeatureEnabled('my_feature', '456', { organizationId: '789' } ); // User 456
For instructions on how to setup the attributes and audiences in the Optimizely UI for this use case, follow this documentation article.
Using attributes and audiences allows you to enable or disable a feature for specific organizations one-by-one. However, this approach does not allow you to randomly rollout to a percentage of the possible organizationIds or do an A/B test on a random sampling of organizationIds.
--
Use Case 2: If you want to run rollout to a random sampling of organizationIds or run an A/B test where a random set of organizations get a particular experience you should pass in the organizationId as the userId parameter to the isFeatureEnabled API:
isFeatureEnabled('my_feature', '789'); // User 123
isFeatureEnabled('my_feature', '789'); // User 456
The userId parameter to isFeatureEnabled is used to randomly bucket the user. Since the userId can accept any string, using the organizationId in this case ensures that both user 123 and 456 will get bucketed into the same experience.
--
Use Case 3: If you want to be able to both run an A/B test across organizations but also have the ability to target only certain organizations, you should combine the methods of the two uses above like the following:
isFeatureEnabled('my_feature', '789', { companyId: '789' } ); // User 123
isFeatureEnabled('my_feature', '789', { companyId: '789' } ); // User 456
This way allows you to manually (rather than randomly) select one-by-one which customer should see an experience or be eligible for an experiment while also allowing you to rollout randomly across organizations or run an A/B test across organizations.

Related

Is there a way to compare each item to a aggreated value?

I'm new to graphQL and Hasura. I'm trying(in Hasura) to let me users provide custom aggregation (ideally in the form of a normal graphQL query) and have then each item the results compared against the aggreation.
Here's a example. Assume I have this schema:
USERTABLE:
userID
Name
Age
City
Country
Gender
HairColor
INCOMETABLE:
userID
Income
I created a relationship in hasura and I can query the data but my users want to do custom scoring of users' income level. For example, one user may want to query the data broken down by country and gender.
For the first example the result maybe:
{Country : Canada
{ gender : female
{ userID: 1,
Name: Nancy Smith,..
#data below is on aggregated results
rank: 1
%fromAverage: 35%
}...
Where I'm struggling is the data showing the users info relative to the aggregated data.
for Rank, I get the order by sorting but I'm not sure how to display the relative ranking and for the %fromAverage, I'm not sure how to do it at all.
Is there a way to do this in Hasura? I suspected that actions might be able to do this but I'm not sure.
You can use track a Postgres view. Your view would have as many fields as you'd like calculated in SQL and tracked as a separate "table" on your graphql api.
I am giving examples below based on a simplification where you have just table called contacts with just a single field called: id which is an auto-integer. I am just adding the id of the current contact to the avg(id) (a useless endeavor to be sure; just to illustrate...). Obviously you can customize the logic to your liking.
A simple implementation of a view would look like this (make sure to hit 'track this' in hasura:
CREATE OR REPLACE VIEW contact_with_custom AS
SELECT id, (SELECT AVG(ID) FROM contacts) + id as custom FROM contacts;
See Extend with views
Another option is to use a computed field. This is just a postgres function that takes a row as an argument and returns some data and it just adds a new field to your existing 'table' in the Graphql API that is the return value of said function. (you don't 'track this' function; once created in the SQL section of Hasura, you add it as a 'computed field' under 'Modify' for the relevant table) Important to note that this option does not allow you to filter by this computed function, whereas in a view, all fields are filterable.
In the same schema mentioned above, a function for a computed field would look like this:
CREATE OR REPLACE FUNCTION custom(contact contacts)
RETURNS Numeric AS $$
SELECT (SELECT AVG(ID) from contacts ) + contact.id
$$ LANGUAGE sql STABLE;
Then you select this function for your computed field, naming it whatever you'd like...
See Computed fields

How would I assign meal event guests per attendee per table per event at a conference in a GraphQL schema?

I'm pondering a rebuild of a meal seating assignment app. I'll make use of GraphQL to query for attendees and their guests of a table at a meal event (assigned seating). The delivered data model looks something like this:
meal event 1
table A
attendee 1
guest 1
...
meal event 2
table L
attendee 1 (no guest this time)
...
An attendee may attend multiple meal events e.g. at a multi-day conference. That attendee may have a guest(s) at meal event(s). This could be another attendee record (two meal tickets, same info), noted as a guest however as an attendee and their guest(s) need to be seated at the same table (don't want spouse on other side of the room for example). Attendees will usually have the same guest(s) at multiple events, however not always due to cost or conflicting guest commitments or wanting to rotate guests per meal, etc.
How would I model this in a GraphQL schema? In the database I'd use join tables. However for client-facing GraphQL queries and schema types, I need to model this a bit differently (I think?). Here's what I have so far:
type Attendee {
name: String
** Can't add guests here as this may change per event
}
type Event {
name: String
tables: [Table]
}
type Table {
name: String
attendees: [Attendee]
** How do I "tree" in guests here for attendees for this table?
}
At this point do I need a join type to get guests per attendee per table per event?
When writing our server code, we typically encapsulate our business logic inside domain models like Event, Table, Attendee or Guest. However, these domain models don't have to have a strict one-to-one mapping with the tables we use to persist their data -- for example, an individual model might aggregate data from multiple tables.
Similarly, your GraphQL types do not have to have a one-to-one mapping to your domain models. It can often make sense to represent the same domain model as multiple types. For example, we can do something like:
type EventAttendee {
id: ID!
name: String!
}
type TableAttendee {
id: ID!
name: String!
guests: [Guest!]!
}
type Table {
id: ID!
attendees: [TableAttendee!]!
}
type Event {
id: ID!
name: String!
attendees: [EventAttendee!]!
tables: [Table!]!
}
Your schema effectively represents multiple graphs or views of your data. Depending on where on that graph your domain model ends up should determine what fields it exposes as a type -- in some contexts, exposing certain properties or relationships makes sense, in others it does not.

How to recognize name of sub-list within list entity?

I have a chatbot powered by Microsoft Bot Framework which is using LUIS service for natural language recognition. One of the supported use cases is to allow users to list their tickets. Since there can multiple different types of tickets, one of the feature requests is to support filtering of these tickets by their type, for example - orders, incidents, etc.
Within LUIS, I have created list entity called ticketType with sub-lists representing individual ticket types and their synonyms:
Next up, I have created intent called listTickets, where I provided following sample utterances:
Finally, I have also created patterns for the listTickets intent to strengthen the recognition:
Now, after training and testing out my model, everything works just fine. Well, almost... The ticketType entity is correctly recognized, but I have no way to distinguish between individual ticket types based on my sub-lists as seen in the test results here:
Question
How do I correctly train my LUIS model and properly create ticketType entity, so that LUIS correctly recognizes also the sub-list? Something like ticketType::order and ticketType::incident?
I have also read about entity roles, however this does not seem to be suitable for my scenario, because:
According to example it is more suitable in situations, when same entity is used multiple times in utterance and roles are used to differentiate between individual entities based on their positions.
In theory I could use roles, but then I would have to train my listTickets intent with every possible sub-list combination to have everything correctly labeled. Would patterns still make sense in this scenario?
I would suggest you test this in Web Chat or whichever channel you will be using. I created a LUIS model based off of yours and, when run thru Web Chat, the information you are seeking is readily available.
In my test, I passed "Display my request" as an utterance to the bot in a previous step. As you can see, "request" is a synonym of "order" which is found in "ticketType" (following your design). I'm able to extract the specific entity from the recognizerResult as well as the normalized values (i.e "sublists").
Hope of help!
const recognizerResult = await this.recognizer.recognize(stepContext.context);
let intent = await LuisRecognizer.topIntent( recognizerResult );
console.log('1', intent )
console.log('2', recognizerResult.entities );
console.log('3', recognizerResult.entities.ticketType );
console.log('4', recognizerResult.luisResult.entities );
1 listTicket
2 { '$instance': { ticketType: [ [Object] ] },
ticketType: [ [ 'order' ] ] }
3 [ [ 'order' ] ]
4 [ { entity: 'request',
type: 'ticketType',
startIndex: 11,
endIndex: 17,
resolution: { values: [Array] } } ]

Dynamics CRM 2011 LinQ to Find New Records

I have a bunch of custom entity records in a List (which comes from a csv file).
What is the best way to check which records are new and create those that are?
The equality check is based on a single text field in this case, but I need to do the same thing elsewhere where the equality check is based on a lookup and 2 text fields.
For arguments sake lets say I was inserting Account records, this is what I currently have:
private void CreateAccounts()
{
var list = this.GetAccounts(); // get the list of Accounts, some may be new
IEnumerable<string> existingAccounts = linq.AccountSet.Select(account => account.AccountNumber); // get all Account numbers in CRM, linq is a serviceContextName variable
var newAccounts = list.Where(account => !existingAccounts.Contains(account.AccountNumber)); // Account numbers not in CRM
foreach (var accountNumber in newAccounts) // go through the new list again and get all the Account info
{
var account = newAccounts.Where(newAccount => newAccount.AccountNumber.Equals(accountNumber)).FirstOrDefault();
service.Create(account);
}
}
Is there a better way to do this?
I seem to be iterating through lists too many times, but it must be better than querying CRM multiple times:
foreach (var account in list)
{
// is this Account already in CRM
// if not create the Account
}
Your current method seems a bit backwards (get everything out of CRM, then compare it to what you have locally), but it may not be too bad depending on how many accounts you have ie < 5000.
For your simple example, you should be able to apply a where in statement.
Joining on multiple fields is a little more tricky. If you are running CRM > R12, you should be able to use the ExecuteMultipleRequests, creating a seperate request for each item in your list, and then batching them all up, so there is one big request "over the wire" to CRM.

LINQ: Joining List<object> and dataset on a comma separated value field?

I am using C# and LINQ and trying to combine two sets of data. The first is a List of a specific type, lets call this Status (List) which is just a class with a bunch of properties one of which includes a comma separated value list of accounts. This is queried from the application database using a stored procedure so I have some flexability as to what is displayed here
For example:
class Status
{
...
public string Accounts {get; set;} (ie. "abcde, qwerty, asdfg")
public string Managers {get; set;}
...
}
The rest of the properties are irrelevant as this is the only field I am joining on.
The second "Accounts" data set is from a web service which I am calling to get a list of "Accounts" and the people associated with each account.
For example:
Account Manager SomeData MoreFields ...
------- ------------------- -------- ---------- ---
abcde Bob Marley Data MoreData ...
qwerty Fred Flinstone Data MoreData ...
So bascially I need to Create a list of Status objects with a CSV list of Manager(s) from the Accounts dataset in the Managers property of Status. Problem is I have no control over what is retruend in this dataset as it is a third party application. So I need to find some way to do this without modifying the "Accounts" data. Unless I do something in memory after getting the dataset from the web service.
I hope this makes sense and I thank you in advance!
What is this "dataset" of which you speak? I don't care where it come from -- I just care what kind of object it is in C#.
I'm going to assume that it's an ICollection, called "accounts"
Next, I'm going to assume that Managers is a CVS list much like Accounts.
Further, I'm only going to create one status object instead of a "list" of them, since you never say what separates one status from another.
var status = new Status();
status.Accounts = string.Join( ", ", from k in accounts select k.Account);
status.Managers = string.Join( ", ", from k in accounts select k.Manager);

Resources