class_docstr: Merges a certain number of adjacent tokens into multi-word tokens, so
  that for example::
  
      "better", "a", "witty", "fool", "than", "a", "foolish", "wit"
  
  with ``ShingleFilter(3, ' ')`` becomes::
  
      'better a witty', 'a witty fool', 'witty fool than', 'fool than a',
      'than a foolish', 'a foolish wit'
  
  This can be used to create fields for pseudo-phrase searching, where if
  all the terms match the document probably contains the phrase, but the
  searching is faster than actually doing a phrase search on individual word
  terms.
  
  If you're using two-word shingles, you should use the functionally
  equivalent ``BiWordFilter`` instead because it's faster than
  ``ShingleFilter``.
code: def __call__(self, tokens):
      size = self.size
      sep = self.sep
      buf = deque()
      atleastone = False
  
      def make_token():
          tk = buf[0]
          tk.text = sep.join([t.text for t in buf])
          if tk.chars:
              tk.endchar = buf[-1].endchar
          return tk
  
      for token in tokens:
          if not token.stopped:
              buf.append(token.copy())
              if len(buf) == size:
                  atleastone = True
                  yield make_token()
                  buf.popleft()
  
      # If no shingles were emitted, that is, the token stream had fewer than
      # 'size' tokens, then emit a single token with whatever tokens there
      # were
      if not atleastone and buf:
          yield make_token()
  
imports: import re
  from collections import deque
  from whoosh.compat import u, text_type
  from whoosh.compat import xrange
  from whoosh.analysis.filters import Filter
label_desc: Use image node_id 2 for calling the ShingleFilter obj's underlying member method code with example usage: obj.__call__(tokens) and returns: tk