Doc produitsMenu

Recettes de configuration du connecteur Salesforce

Cette rubrique offre des solutions de configuration du connecteur Salesforce pour diverses situations que vous pouvez rencontrer lorsque vous souhaitez optimiser la facilité de recherche de votre contenu Salesforce.

Indexation de toutes les versions et états de Knowledge Base

Un article de Knowledge Base (KB) a un état et une version. Par défaut, le connecteur extrait la dernière version d’un article avec l’état en ligne (publié).

Note : Par défaut, le connecteur ne supprime pas les documents qui sont archivés, mais vous pouvez modifier ce comportement (voir Exclure les articles archivés de Knowledge Base).

Les champs PublishStatus et IsLatestVersion contrôlent, respectivement, quelle version et quel état de l’article sont extraits. Extraire toutes les versions et états signifie :

  • Extraire les articles en ligne

  • Extraire les articles brouillons

  • Extraire les derniers articles archivés

  • Extraire les autres articles archivés

L’exemple suivant d’un fichier de configuration ObjectsToGet pour un article de type Documentation obtient les articles Draft, Online, et Archived.

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfQuery xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Query>
    <ObjectName>Documentation__ka</ObjectName>
    <Fields>
      <string>Id</string>
      <string>LastPublishedDate</string>
    </Fields>
  </Query>
  <Query>
    <ObjectName>Documentation__kav</ObjectName>
    <Fields>
      <string>Id</string>
      <string>Title</string>
      <string>PublishStatus</string>
      <string>IsLatestVersion</string>
    </Fields>
    <Conditions>
      <QueryCondition>
        <Field>PublishStatus</Field>
        <Operator>=</Operator>
        <Value>'Archived'</Value>
      </QueryCondition>
      <QueryCondition>
        <Field>IsLatestVersion</Field>
        <Operator>=</Operator>
        <Value>False</Value>
      </QueryCondition>
    </Conditions>
  </Query>
  <Query>
    <ObjectName>Documentation__kav</ObjectName>
    <Fields>
      <string>Id</string>
      <string>Title</string>
      <string>PublishStatus</string>
      <string>IsLatestVersion</string>
    </Fields>
    <Conditions>
      <QueryCondition>
        <Field>PublishStatus</Field>
        <Operator>=</Operator>
        <Value>'Archived'</Value>
      </QueryCondition>
      <QueryCondition>
        <Field>IsLatestVersion</Field>
        <Operator>=</Operator>
        <Value>True</Value>
      </QueryCondition>
    </Conditions>
  </Query>
  <Query>
    <ObjectName>Documentation__kav</ObjectName>
    <Fields>
      <string>Id</string>
      <string>Title</string>
      <string>PublishStatus</string>
      <string>IsLatestVersion</string>
    </Fields>
    <Conditions>
      <QueryCondition>
        <Field>PublishStatus</Field>
        <Operator>=</Operator>
        <Value>'Draft'</Value>
      </QueryCondition>
    </Conditions>
  </Query>
  <Query>
    <ObjectName>Documentation__kav</ObjectName>
    <Fields>
      <string>Id</string>
      <string>Title</string>
      <string>PublishStatus</string>
      <string>IsLatestVersion</string>
    </Fields>
    <Conditions>
      <QueryCondition>
        <Field>PublishStatus</Field>
        <Operator>=</Operator>
        <Value>'Online'</Value>
      </QueryCondition>
    </Conditions>
  </Query>
</ArrayOfQuery>

Exclure les articles archivés de Knowledge Base

Les articles KB archivés peuvent être supprimés dans une actualisation incrémentale à l’aide d’une requête destructive tel qu’affiché dans l’exemple suivant de fichier de configuration ObjectsToGet. Cette requête supprimera les documents précédemment indexés de l’index plutôt que de les ajouter ou les mettre à jour.

Important :

  • Vous n’avez pas besoin de spécifier des champs ou des relations pour des requêtes destructives. Les enregistrements retrouvés seront seulement supprimés. Garder vos ObjectsToGet brefs aide pour le débogage.

  • Les objets supprimés non-réplicables ne peuvent être supprimés par une requête destructrice.

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfQuery xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Query>
    <ObjectName>Documentation__ka</ObjectName>
    <Fields>
      <string>Id</string>
      <string>LastPublishedDate</string>
    </Fields>
  </Query>
  <Query>
    <ObjectName>Documentation__kav</ObjectName>
    <Fields>
      <string>Id</string>
      <string>Title</string>
    </Fields>
  </Query>
  <Query>
    <ObjectName>Documentation__kav</ObjectName>
    <FoundRecordsAreDeleted>true</FoundRecordsAreDeleted>
    <Conditions>
      <QueryCondition>
        <Field>PublishStatus</Field>
        <Operator>=</Operator>
        <Value>'Archived'</Value>
      </QueryCondition>
      <QueryCondition>
        <Field>IsLatestVersion</Field>
        <Operator>=</Operator>
        <Value>True</Value>
      </QueryCondition>
    </Conditions>
  </Query>
  <Query>
    <ObjectName>Documentation__kav</ObjectName>
    <FoundRecordsAreDeleted>true</FoundRecordsAreDeleted>
    <Conditions>
      <QueryCondition>
        <Field>PublishStatus</Field>
        <Operator>=</Operator>
        <Value>'Archived'</Value>
      </QueryCondition>
      <QueryCondition>
        <Field>IsLatestVersion</Field>
        <Operator>=</Operator>
        <Value>False</Value>
      </QueryCondition>
    </Conditions>
  </Query>
</ArrayOfQuery>

Indexation de pièces jointes Knowledge Base

Le connecteur Salesforce traite les pièces jointes d’articles KB différemment en comparaison avec des objets normaux (qui se réfèrent à l’objet Attachment). Les pièces jointes d’articles KB sont automatiquement indexées lorsque les champs qui se terminent par __Name__s sont spécifiés dans le fichier de configuration ObjectsToGet tel que dans l’exemple suivant pour indexer la pièce jointe d’un article de type Documentation.

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfQuery xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Query>
    <ObjectName>Documentation__ka</ObjectName>
    <Fields>
      <string>Id</string>
    </Fields>
  </Query>
  <Query>
    <ObjectName>Documentation__kav</ObjectName>
    <Fields>
      <string>Id</string>
      <string>Attachment__Name__s</string>
    </Fields>
  </Query>
</ArrayOfQuery>

Une entrée dans le fichier de correspondance doit également exister. Comme vous pouvez le voir ci-dessous, le nom de la correspondance est [NameOfArticleType] Attachment:

<?xml version="1.0" encoding="Windows-1252" ?>
<SalesForce>
  ...
  <Mapping type="Documentation Attachment">
    <ContentType>binarydata</ContentType>
    ...
  </Mapping>
  ...
</SalesForce>

Extraire des enregistrements avec des relations parentes qui doivent être mises à jour de façon incrémentale

Il est commun de devoir indexer un enregistrement avec des champs qui désignent un parent d’une relation enfante. La façon traditionnelle d’accomplir ceci est d’utiliser les éléments <ChildRelationships/>, <ParentRelationships/> ou <PolymorphicRelationships/> dans une définition Query. Toutefois, utiliser ces éléments vous donnera des enregistrements qui ne seront pas actualisés correctement. Lorsque l’enregistrement A désigne un champ de l’enregistrement B et celui-ci change, l’enregistrement A ne sera pas mis à jour dans une actualisation incrémentale.

Prenons un exemple spécifique, où Opportunity fait référence à un nom Account. L’exemple suivant de fichier de configuration ObjectsToGet produit un enregistrement Opportunity avec les métadonnées ["Id", "Account.Name"] :

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfQuery xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Query>
    <ObjectName>Opportunity</ObjectName>
    <Fields>
      <string>Id</string>
    </Fields>
    <ParentRelationships>
      <ParentRelationship>
        <RelationshipName>Account</RelationshipName>
        <Fields>
          <string>Name</string>
        </Fields>
      </ParentRelationship>
    </ParentRelationships>
  </Query>
</ArrayOfQuery>

Vous pouvez résoudre ce problème à l’aide de clés étrangères (voir À propos des clés étrangères). Vous devez créer deux requêtes plutôt qu’une. L’exemple suivant de fichier de configuration ObjectsToGet produit un enregistrement Opportunity avec les métadonnées ["Id", "Account.Name"], et un enregistrement Account avec les métadonnées ["Id", "Name"].

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfQuery xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Query>
    <ObjectName>Opportunity</ObjectName>
    <Fields>
      <string>AccountId</string>
    </Fields>
  </Query>
  <Query>
    <ObjectName>Account</ObjectName>
    <Fields>
      <string>Id</string>
      <string>Name</string>
    </Fields>
  </Query>
</ArrayOfQuery>

Avec des métadonnées liées à des champs tel qu’affiché ci-dessous :

Opportunity
  AccountId: sfaccountid
Account
  Id: sfaccountid
  Name: sfaccountname

Vous devez modifier le fichier [Index_Path]\Config\Config.txt de CES pour lier les deux enregistrements à l’aide de clés étrangères, tel qu’affiché ci-dessous :

Important : Modifier manuellement le fichier de configuration CES peut avoir des conséquences importantes, particulièrement lorsque votre déploiement de Coveo inclut un ou plusieurs serveurs miroir. Contactez Coveo Support pour obtenir de l'aide pour installer les clés étrangères.

<PhysicalIndex>
  ...
  <ForeignKeys>
    <ForeignKey ID="1">
      <KeyField>sfaccountid</KeyField>
      <ValueField>sfaccountname</ValueField>
      <FreeTextSearch>false</FreeTextSearch>
    </ForeignKey>
  </ForeignKeys>
  ...
</PhysicalIndex>

Extraire une relation enfante à utiliser pour le pliage

L’extraction de relations enfantes qui sont utilisées dans le pliage (pas de facette) afin qu’elles jouent bien avec l’actualisation incrémentale est effectuée par le pliage de résultats (voir À propos des résultats en accordéon).

Prenons un exemple spécifique, où un Case fait référence à CaseComments. De façon similaire au cas de l’extraction de la relation parente, évitez d’utiliser l’élément <ChildRelationships/> tel qu’affiché ci-dessous et de produire un enregistrement Case avec les métadonnées ["Id", "CaseComments.CommentBody"].

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfQuery xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Query>
    <ObjectName>Case</ObjectName>
    <Fields>
      <string>Id</string>
    </Fields>
    <ChildRelationships>
      <Query>
        <ObjectName>CaseComments</ObjectName>
        <Fields>
          <string>CommentBody</string>
        </Fields>
      </Query>
    </ChildRelationships>
  </Query>
</ArrayOfQuery>

Utilisez plutôt au moins deux requêtes :

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfQuery xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Query>
    <ObjectName>Case</ObjectName>
    <Fields>
      <string>Id</string>
    </Fields>
  </Query>
  <Query>
    <ObjectName>CaseComment</ObjectName>
    <Fields>
      <string>Id</string>
      <string>ParentId</string>
    </Fields>
  </Query>
</ArrayOfQuery>

Maintenant, il ne reste qu’à utiliser la composante de pliage d’interface d’utilisateur pour plier CaseComments sous Case documents comme dans Coveo JavaScript Search (voir Folding Component).

Extraire une relation enfante à utiliser pour augmenter ou réduire les résultats de requêtes

L’extraction de relations enfantes qui sont utilisées pour augmenter ou réduire le nombre de résultats (ce qui veut dire : pas de facette) afin qu’elles jouent bien avec l’actualisation incrémentale est effectuée par des requêtes imbriquées.

Comme dans d’autres cas, évitez d’utiliser l’élément <ChildRelationships/> et utilisez plutôt au moins deux requêtes. Vous pouvez utiliser l’exemple de la recette précédente pour le fichier de configuration ObjectsToGet.

Vous pouvez alors utiliser la requête imbriquée dans les paramètres de la requête ou dans le langage extensible de la requête de l’interface utilisateur.

Un cas d’utilisation simple mais réel est de rechercher les documents Cases ET CaseComments mais retourne seulement Cases tel que suit :

@sfid=[[@syssfcaseid] @objecttype=CaseComment q] // Where q is the keyword.

Minimisation des appels d’API et de la pré-extraction de descriptions d’objets

Par défaut, le connecteur pré-extrait les descriptions de chaque objet dans l’organisation Salesforce pour minimiser le nombre d’appels d’API utilisés selon les hypothèses suivantes :

  • Extraire un objet coûte 1 appel d’API.

  • Pré-extraire 200 objets coûte 1 appel d’API.

  • Une organisation a habituellement 500-1 000 objets.

  • Un fichier de configuration ObjectsToGet recherche typiquement 10-20 objets.

Exemple : Une organisation a 1 000 objets et la requête de source dans le fichier de configuration ObjectsToGet inclut 20 objets. Une actualisation incrémentale est planifiée à chaque 5 minutes, donc 24 h / 5 min = 288 refreshes per day.

  • Sans pré-extraction : 20 obj. * 288 incr. refr. = 5760 calls per day.

  • Avec pré-extraction : (1000 obj. / 200 obj. per prefetch) * 288 incr. refr. = 1440 calls per day.

Utiliser la pré-extraction consomme quatre fois moins d’appels dans ce cas.

Pré-extraire des descriptions d’objets ne minimise pas toujours les appels d’API.

Exemple : Une organisation a 2 000 objets et la requête de source dans le fichier de configuration ObjectsToGet inclut 5 objets. Une actualisation incrémentale est planifiée à chaque 5 minutes, donc 24 h / 5 min = 288 refreshes per day.

  • Sans pré-extraction : 5 obj. * 288 incr. refr. = 1440 calls per day.

  • Avec pré-extraction : (2000 obj. / 200 obj. per prefetch) * 288 incr. refr. = 2880 calls per day.

Dans ce scénario, éteindre la pré-extraction est bénéfique.

Vous pouvez éteindre la pré-extraction en définissant le paramètre de source caché de Salesforce PrefetchObjectDescriptions à False (voir PrefetchObjectDescriptions). La formule pour déterminer la valeur optimale du paramètre PrefetchObjectDescriptions est :

PrefetchObjectDescriptions = ObjectsToGet.Objects.Count > Organization.Objects.Count / 200

Extraire des enregistrements plus rapidement avec le coureur Turbo Mode

Le comportement par défaut du connecteur pendant l’extraction d’enregistrements d’une requête est :

  1. Faire un appel d’API pour obtenir la première page, puis attendre les enregistrements.

  2. Traiter les enregistrements.

  3. Faire un appel d’API pour obtenir la deuxième page, et ainsi de suite.

Pour certaines requêtes, ce processus peut prendre des jours. La solution alternative, dans de tels cas, est d’utiliser le coureur TurboMode.

Quand l’utiliser

Prenez en considération l’utilisation du coureur TurboMode lorsque :

  • La requête prend généralement beaucoup de temps à exécuter.

  • Une enquête a démontré que Salesforce retourne des petites pages de résultats (ex. : 1-5 éléments par page).

  • Une enquête a démontré que Salesforce prend beaucoup de temps pour générer une page (ex. : 1-3 secondes par page).

  • Les désavantages suivant sont acceptables :

    • Davantage d’appels d’API sont nécessaires.

    • Davantage de mémoire libre est nécessaire.

    • Ne fonctionne pas pour les requêtes avec une condition IN dans Id.

    • Les éléments extraits ne sont pas triés (donc interrompre/reprendre le connecteur dans cette requête va ré-extraire tous les éléments).

Important : Une source Salesforce qui utilise le coureur TurboMode pour une de ses requêtes doit avoir ses propres paramètres de connexion dédiés pour empêcher des erreurs pour d’autres sources exécutées en parallèle.

Comment l’utiliser

Vous pouvez activer le coureur TurboMode dans le fichier de configuration ObjectsToGet comme suit :

<Query>
  <Runner>TurboMode</Runner>
  ...
</Query>

Comment il fonctionne

Avec le coureur de requête Turbo Mode, le connecteur Salesforce exécute deux types de requêtes parallèlement :

  • Extraction d’identifiant

    Une requête extrait de façon asynchrone tous les identifiants des enregistrements et les met dans une file d’attente. Cette requête est exécutée par un fil et est rapide, peu importe la véritable requête à exécuter.

  • Extraction d’enregistrements

    Plusieurs requêtes, qui représentent la véritable requête à exécuter, prennent jusqu’à 200 identifiants chacune, extraient les enregistrements, et les met dans une autre file d’attente. Ces requêtes sont lentes, mais sont exécutées parallèlement par N fils. En pratique, N = 8, limité par une limite stricte de Salesforce (voir Query Locator).

Le coureur de requêtes coordonne les fils et sert les enregistrements extraits à l’appelant en tant que IEnumerable simple et à lecture unique.

Exemple : La requête suivante s’applique à 100 000 enregistrements.

SELECT Id, Subject, (SELECT Email FROM Shares) FROM Account

Avec le coureur par défaut, si Salesforce envoie des pages de 5 enregistrements à chaque 3 secondes, il faudra plus de 16 heures pour extraire tous les enregistrements.

Avec le coureur TurboMode, la requête d’extraction d’identifiant est :

SELECT Id FROM Account

et les requêtes d’extraction d’enregistrement sont :

SELECT Id, Subject, (SELECT Email FROM Shares) FROM Account WHERE Id IN (...)

Note : Entre l’extraction d’identifiants et celle d’enregistrements, des enregistrements peuvent être supprimés dans Salesforce. Dans ce cas, les identifiants sont tout simplement ignorés par Salesforce.

Réduire la taille du package de métadonnées en contrôlant les parents des objets ContentVersion et Attachment

Les objets ContentVersion et Attachment recherchent leurs objets parents pour résoudre des permissions d’enregistrement. Le comportement par défaut du connecteur est d’extraire le package de métadonnées pour tous les parents de ces objets pour déterminer leurs modèles de partage. Pour certaines organisations Salesforce, le package de métadonnées extrait peut devenir trop gros.

Vous pouvez spécifier un InCondition dans le champ ParentObjectType dans le fichier de configuration ObjectsToGet pour définir les parents d’un enregistrement à des valeurs spécifiques et, par conséquent, réduire la taille du package de métadonnées à extraire.

Important : Avec cette technique, les permissions d’enregistrements ne sont pas entièrement indexées. Seuls les enregistrements parents d’objets parents spécifiés sont considérés comme déterminant les permissions d’enregistrements.

Exemple : Avec la requête suivante, les permissions d’enregistrement ContentVersion sont l’agrégation d’enregistrements parents Case et Opportunity.

<Query>
  <ObjectName>ContentVersion</ObjectName>
  <Fields>
    <string>Id</string>
  </Fields>
  <Conditions>
    <InCondition>
      <Field>ParentObjectType</Field>
      <AllowedValues>
        <SoqlString>Case</SoqlString>
        <SoqlString>Opportunity</SoqlString>
      </AllowedValues>
    </InCondition>
  </Conditions>
</Query>

Choisir le champ optimal de date de modification d’enregistrement

Pendant l’indexation d’enregistrements, vous pouvez choisir à partir de plusieurs champs, tels que ceux-ci afin de définir la date de modification d’un enregistrement :

  • SystemModstamp : Mis à jour lorsqu’un utilisateur ou un script modifie l’enregistrement.

  • LastModifiedDate : Mis à jour lorsqu’un utilisateur modifie l’enregistrement.

  • CreatedDate : Défini lorsque l’enregistrement est créé.

Le champ prioritaire est SystemModstamp parce qu’il est mis à jour plus souvent.

Exemple : Dans un scénario fréquent où un Case est assigné à un utilisateur ou une file d’attente en raison de règles d’assignation, le champ OwnerId est modifié par un script interne. Le champ SystemModstamp est modifié, mais pas LastModifiedDate et CreatedDate.

Supprimer les premiers zéros d’un champ

Lorsqu’un champ est un Auto Number, le connecteur produit une métadonnée supplémentaire avec le suffixe __stripped qui contient la valeur sans les premiers zéros. Vous pouvez utiliser ce champ lorsque vous souhaitez afficher ou utiliser les valeurs sans les premiers zéros.

Exemple :

MyField__c: 0000123
MyField__c__stripped: 123

Utiliser le convertisseur de champ de devise

Le connecteur peut interpréter les devises monétaires. Lorsque l’utilisateur qui analyse la source est configuré en un mode Single Currency, des métadonnées supplémentaires sont générées pour des enregistrements.

Lorsqu’un champ est currency, sa valeur est convertie en la devise de l’utilisateur et une nouvelle métadonnée est créée avec le suffixe _converted.

Utilisation de FiscalYearResolver

Lorsqu’un champ est date et a une valeur, le programme de résolution d’année fiscale créé des métadonnées supplémentaires dans les enregistrements avec les suffixes suivants :

__fiscal_year
__fiscal_quarter
__fiscal_month
__fiscal_week
__fiscal_pretty_quarter

Vous pouvez désactiver la création de ces métadonnées supplémentaires en définissant le paramètre de source caché LoadFiscalYearMetadata à False (voir LoadFiscalYearMetadata (Booléen)).

Réparer l’erreur de suivi de flux

Vous pouvez obtenir une erreur de source Salesforce typique qui ressemble à ceci :

Error with ID 'SALESFORCE_INVALID_QUERY': Cannot find child relationship 'Feeds' on object 'Products/Licenses' ('Case'). Make sure 'Feed Tracking' is enabled for this object in Salesforce.

Pendant l’indexation d’éléments Chatter, le connecteur vérifie le parent lié à un champ dans tous les objets Chatter pour différencier un objet Chatter d’un objet normal. Certains objets n’ont pas la relation enfante 'Feeds' parce que le suivi de flux est désactivé. Cette relation est la façon dont le connecteur obtient des objets liés à Chatter.

Vous pouvez résoudre ce type d’erreur en activant le suivi de flux (voir Customizing Chatter Feed Tracking).

Indexer davantage que les types FeedItem intégrés

Par défaut, le connecteur indexe les types suivants de flux Chatter : TextPost, LinkPost, ContentPost, et PollPost.

Dans le fichier de configuration ObjectsToGet, vous pouvez remplacer ce comportement en utilisant un InCondition dans la définition de requête de FeedItem.

Exemple : La requête suivante de fichier de configuration ObjectsToGet n’indexe que les FeedItem des types TextPost et TrackedChanged.

<Query>
  <ObjectName>FeedItem</ObjectName>
  <Fields>
    <string>Id</string>
  </Fields>
  <Conditions>
    <InCondition>
      <Field>Type</Field>
      <AllowedValues>
        <SoqlString>TextPost</SoqlString>
        <SoqlString>TrackedChange</SoqlString>
      </AllowedValues>
    </InCondition>
  </Conditions>
</Query>