docs: @Override
  	public Set<ResourceIndexedSearchParamString> extractSearchParamStrings(ResourceTable theEntity, IBaseResource theResource) {
  		HashSet<ResourceIndexedSearchParamString> retVal = new HashSet<ResourceIndexedSearchParamString>();
  
  		String resourceName = getContext().getResourceDefinition(theResource).getName();
  
  		Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
  		for (RuntimeSearchParam nextSpDef : searchParams) {
  			if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.STRING) {
  				continue;
  			}
  
  			String nextPath = nextSpDef.getPath();
  			String nextSpName = nextSpDef.getName();
  
  			if (isBlank(nextPath)) {
  
  				// TODO: implement phonetic, and any others that have no path
  
  				if ("Questionnaire".equals(resourceName) && nextSpDef.getName().equals("title")) {
  					Questionnaire q = (Questionnaire) theResource;
  					String title = q.getGroup().getTitle();
  					addSearchTerm(theEntity, retVal, nextSpName, title);
  				}
  				continue;
  			}
  
  			for (Object nextObject : extractValues(nextPath, theResource)) {
  				if (nextObject == null || ((IDatatype) nextObject).isEmpty()) {
  					continue;
  				}
  
  				boolean multiType = false;
  				if (nextPath.endsWith("[x]")) {
  					multiType = true;
  				}
  
  				if (nextObject instanceof IPrimitiveDatatype<?>) {
  					IPrimitiveDatatype<?> nextValue = (IPrimitiveDatatype<?>) nextObject;
  					String searchTerm = nextValue.getValueAsString();
  					addSearchTerm(theEntity, retVal, nextSpName, searchTerm);
  				} else {
  					if (nextObject instanceof BaseHumanNameDt) {
  						ArrayList<StringDt> allNames = new ArrayList<StringDt>();
  						HumanNameDt nextHumanName = (HumanNameDt) nextObject;
  						allNames.addAll(nextHumanName.getFamily());
  						allNames.addAll(nextHumanName.getGiven());
  						for (StringDt nextName : allNames) {
  							addSearchTerm(theEntity, retVal, nextSpName, nextName.getValue());
  						}
  					} else if (nextObject instanceof AddressDt) {
  						ArrayList<StringDt> allNames = new ArrayList<StringDt>();
  						AddressDt nextAddress = (AddressDt) nextObject;
  						allNames.addAll(nextAddress.getLine());
  						allNames.add(nextAddress.getCityElement());
  						allNames.add(nextAddress.getStateElement());
  						allNames.add(nextAddress.getCountryElement());
  						allNames.add(nextAddress.getPostalCodeElement());
  						for (StringDt nextName : allNames) {
  							addSearchTerm(theEntity, retVal, nextSpName, nextName.getValue());
  						}
  					} else if (nextObject instanceof ContactPointDt) {
  						ContactPointDt nextContact = (ContactPointDt) nextObject;
  						if (nextContact.getValueElement().isEmpty() == false) {
  							addSearchTerm(theEntity, retVal, nextSpName, nextContact.getValue());
  						}
  					} else {
  						if (!multiType) {
  							throw new ConfigurationException("Search param " + nextSpName + " is of unexpected datatype: " + nextObject.getClass());
  						}
  					}
  				}
  			}
  		}
  
  		return retVal;
  	}