Word count on KBA

Tilly Penn
Tera Contributor

I'm trying to get some statistics on our Knowledge Articles.  I need to know word count, average length of the body, average number of characters, shortest article, longest article etc.  Can anybody help?

2 ACCEPTED SOLUTIONS

Paul Curwen
Giga Sage

At the moment there is nothing OOTB that does this. When you edit a KB you can actually see the word count (and you can see characters count by clicking on it)  but it is not available to report on etc.

 

word.PNG

 

 

There is a Service Portal word count function available for free on Share though. See: 

 

https://developer.servicenow.com/connect.do#!/share/contents/2421893_add_wordcount_and_print_functio...

 

You should be able to re-purpose the code for what you need. 

 

There is an Idea raised in the Idea portal for this so worth an upvote see: 

 

https://support.servicenow.com/ideas?id=view_idea&sysparm_idea_id=85b2de421b87c990587a11751a4bcb3b&s...

 

If helpful please mark as Helpful/Correct

 

idea.PNG

***If Correct/Helpful please take time mark as Correct/Helpful. It is much appreciated.***

Regards

Paul

View solution in original post

Averell
ServiceNow Employee
ServiceNow Employee

Adding such functionality in ServiceNow is not a big thing:

If you want to create statistics, you must first collect the data. The best way to do this is to extend the knowledge table with the appropriate fields.

 

Averell_0-1673970501645.png

Then you add these fields to your form so that you can see it.

Averell_1-1673970675096.png

Now it gets a bit complicated because unfortunately the Knowledge Body field is an HTML field. So you can't just count the content, you have to omit the whole format overhead.
The easiest way to solve the task is to build a flow in the Flow Designer.

  1. You create a new flow that is triggered when a knowledge article is created or updated.
  2. You pass the content to a script that does the evaluations for you (I'll describe this below).
  3. And with the result of the script you make an update on your three fields.

Averell_2-1673971186727.png

The script can only be expressed as JavaScript. You need a programmer for that. But it is not so complicated. You create an Action in the Flow Designer, define the Input and Output variables and then you insert the script.

Averell_3-1673971806647.png

You can copy it from here.

(function execute(inputs, outputs) {
  'use strict'

  liveElements = []
  const each = Array.prototype.forEach

  counts  = count(inputs.text)

  outputs.paragraphs= counts.paragraphs
  outputs.words= counts.words
  outputs.characters= counts.characters

  
  function decode (string) {
    const output = []
  	counter = 0
  	const length = string.length

  	while (counter < length) {
  		const value = string.charCodeAt(counter++)

  		if (value >= 0xD800 && value <= 0xDBFF && counter < length) {

  			// It's a high surrogate, and there is a next character.

  			const extra = string.charCodeAt(counter++)

  			if ((extra & 0xFC00) == 0xDC00) { // Low surrogate.
  				output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000)
  			} else {

  				// It's an unmatched surrogate; only append this code unit, in case the
  				// next code unit is the high surrogate of a surrogate pair.

  				output.push(value)
  				counter--
  			}
  		} else {
  			output.push(value)
  		}
  	}

  	return output
  }


  function count (target, options) {
    original = '' + (typeof target === 'string' ? target : ('value' in target ? target.value : target.textContent))
    options = options || {}

 
    original = original.replace(/<\/?[a-z][^>]*>/gi, '')

    if (options.ignore) {
        each.call(options.ignore, function (i) {
            original = original.replace(i, '')
        })
    }

    const trimmed = original.trim()

    return {
      paragraphs: trimmed ? (trimmed.match(options.hardReturns ? /\n{2,}/g : /\n+/g) || []).length + 1 : 0,
      words: trimmed ? (trimmed.replace(/['";:,.?¿\-!¡]+/g, '').match(/\S+/g) || []).length : 0,
      characters: trimmed ? decode(trimmed.replace(/\s/g, '')).length : 0,
    }
  }


})(inputs, outputs);

Now you only have to publish and activate the action and the flow, and then all numbers will be automatically written into the corresponding fields as soon as you change something in an article.
And because you now have it in the table, you can do all the reports on it that you want to have.

Averell_4-1673973096299.png

Quite simple, isn't it?

 

View solution in original post

2 REPLIES 2

Paul Curwen
Giga Sage

At the moment there is nothing OOTB that does this. When you edit a KB you can actually see the word count (and you can see characters count by clicking on it)  but it is not available to report on etc.

 

word.PNG

 

 

There is a Service Portal word count function available for free on Share though. See: 

 

https://developer.servicenow.com/connect.do#!/share/contents/2421893_add_wordcount_and_print_functio...

 

You should be able to re-purpose the code for what you need. 

 

There is an Idea raised in the Idea portal for this so worth an upvote see: 

 

https://support.servicenow.com/ideas?id=view_idea&sysparm_idea_id=85b2de421b87c990587a11751a4bcb3b&s...

 

If helpful please mark as Helpful/Correct

 

idea.PNG

***If Correct/Helpful please take time mark as Correct/Helpful. It is much appreciated.***

Regards

Paul

Averell
ServiceNow Employee
ServiceNow Employee

Adding such functionality in ServiceNow is not a big thing:

If you want to create statistics, you must first collect the data. The best way to do this is to extend the knowledge table with the appropriate fields.

 

Averell_0-1673970501645.png

Then you add these fields to your form so that you can see it.

Averell_1-1673970675096.png

Now it gets a bit complicated because unfortunately the Knowledge Body field is an HTML field. So you can't just count the content, you have to omit the whole format overhead.
The easiest way to solve the task is to build a flow in the Flow Designer.

  1. You create a new flow that is triggered when a knowledge article is created or updated.
  2. You pass the content to a script that does the evaluations for you (I'll describe this below).
  3. And with the result of the script you make an update on your three fields.

Averell_2-1673971186727.png

The script can only be expressed as JavaScript. You need a programmer for that. But it is not so complicated. You create an Action in the Flow Designer, define the Input and Output variables and then you insert the script.

Averell_3-1673971806647.png

You can copy it from here.

(function execute(inputs, outputs) {
  'use strict'

  liveElements = []
  const each = Array.prototype.forEach

  counts  = count(inputs.text)

  outputs.paragraphs= counts.paragraphs
  outputs.words= counts.words
  outputs.characters= counts.characters

  
  function decode (string) {
    const output = []
  	counter = 0
  	const length = string.length

  	while (counter < length) {
  		const value = string.charCodeAt(counter++)

  		if (value >= 0xD800 && value <= 0xDBFF && counter < length) {

  			// It's a high surrogate, and there is a next character.

  			const extra = string.charCodeAt(counter++)

  			if ((extra & 0xFC00) == 0xDC00) { // Low surrogate.
  				output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000)
  			} else {

  				// It's an unmatched surrogate; only append this code unit, in case the
  				// next code unit is the high surrogate of a surrogate pair.

  				output.push(value)
  				counter--
  			}
  		} else {
  			output.push(value)
  		}
  	}

  	return output
  }


  function count (target, options) {
    original = '' + (typeof target === 'string' ? target : ('value' in target ? target.value : target.textContent))
    options = options || {}

 
    original = original.replace(/<\/?[a-z][^>]*>/gi, '')

    if (options.ignore) {
        each.call(options.ignore, function (i) {
            original = original.replace(i, '')
        })
    }

    const trimmed = original.trim()

    return {
      paragraphs: trimmed ? (trimmed.match(options.hardReturns ? /\n{2,}/g : /\n+/g) || []).length + 1 : 0,
      words: trimmed ? (trimmed.replace(/['";:,.?¿\-!¡]+/g, '').match(/\S+/g) || []).length : 0,
      characters: trimmed ? decode(trimmed.replace(/\s/g, '')).length : 0,
    }
  }


})(inputs, outputs);

Now you only have to publish and activate the action and the flow, and then all numbers will be automatically written into the corresponding fields as soon as you change something in an article.
And because you now have it in the table, you can do all the reports on it that you want to have.

Averell_4-1673973096299.png

Quite simple, isn't it?