summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChayim <chayim@users.noreply.github.com>2021-10-25 17:18:27 +0300
committerGitHub <noreply@github.com>2021-10-25 17:18:27 +0300
commitddd1496782cc8eb15fca6c9059b2b08a03efe366 (patch)
treeab907bd2fd2f7cfb951e750de69ea9d4478a5b9c
parent3946da29d7e451a20289fb6e282516fa24e402af (diff)
downloadredis-py-ddd1496782cc8eb15fca6c9059b2b08a03efe366.tar.gz
Adding support for redisearch (#1640)
-rw-r--r--redis/commands/redismodules.py9
-rw-r--r--redis/commands/search/__init__.py96
-rw-r--r--redis/commands/search/_util.py10
-rw-r--r--redis/commands/search/aggregation.py408
-rw-r--r--redis/commands/search/commands.py704
-rw-r--r--redis/commands/search/document.py16
-rw-r--r--redis/commands/search/field.py94
-rw-r--r--redis/commands/search/indexDefinition.py80
-rw-r--r--redis/commands/search/query.py328
-rw-r--r--redis/commands/search/querystring.py324
-rw-r--r--redis/commands/search/reducers.py178
-rw-r--r--redis/commands/search/result.py75
-rw-r--r--redis/commands/search/suggestion.py54
-rw-r--r--tasks.py1
-rw-r--r--tests/conftest.py15
-rw-r--r--tests/test_json.py50
-rw-r--r--tests/test_search.py1219
-rw-r--r--tests/testdata/titles.csv4861
-rwxr-xr-xtests/testdata/will_play_text.csv.bz2bin0 -> 2069623 bytes
-rw-r--r--tox.ini2
20 files changed, 8494 insertions, 30 deletions
diff --git a/redis/commands/redismodules.py b/redis/commands/redismodules.py
index fb53107..2c9066a 100644
--- a/redis/commands/redismodules.py
+++ b/redis/commands/redismodules.py
@@ -15,3 +15,12 @@ class RedisModuleCommands:
from .json import JSON
jj = JSON(client=self, encoder=encoder, decoder=decoder)
return jj
+
+ def ft(self, index_name="idx"):
+ """Access the search namespace, providing support for redis search."""
+ if 'search' not in self.loaded_modules:
+ raise ModuleError("search is not a loaded in the redis instance.")
+
+ from .search import Search
+ s = Search(client=self, index_name=index_name)
+ return s
diff --git a/redis/commands/search/__init__.py b/redis/commands/search/__init__.py
new file mode 100644
index 0000000..8320ad4
--- /dev/null
+++ b/redis/commands/search/__init__.py
@@ -0,0 +1,96 @@
+from .commands import SearchCommands
+
+
+class Search(SearchCommands):
+ """
+ Create a client for talking to search.
+ It abstracts the API of the module and lets you just use the engine.
+ """
+
+ class BatchIndexer(object):
+ """
+ A batch indexer allows you to automatically batch
+ document indexing in pipelines, flushing it every N documents.
+ """
+
+ def __init__(self, client, chunk_size=1000):
+
+ self.client = client
+ self.execute_command = client.execute_command
+ self.pipeline = client.pipeline(transaction=False, shard_hint=None)
+ self.total = 0
+ self.chunk_size = chunk_size
+ self.current_chunk = 0
+
+ def __del__(self):
+ if self.current_chunk:
+ self.commit()
+
+ def add_document(
+ self,
+ doc_id,
+ nosave=False,
+ score=1.0,
+ payload=None,
+ replace=False,
+ partial=False,
+ no_create=False,
+ **fields
+ ):
+ """
+ Add a document to the batch query
+ """
+ self.client._add_document(
+ doc_id,
+ conn=self.pipeline,
+ nosave=nosave,
+ score=score,
+ payload=payload,
+ replace=replace,
+ partial=partial,
+ no_create=no_create,
+ **fields
+ )
+ self.current_chunk += 1
+ self.total += 1
+ if self.current_chunk >= self.chunk_size:
+ self.commit()
+
+ def add_document_hash(
+ self,
+ doc_id,
+ score=1.0,
+ replace=False,
+ ):
+ """
+ Add a hash to the batch query
+ """
+ self.client._add_document_hash(
+ doc_id,
+ conn=self.pipeline,
+ score=score,
+ replace=replace,
+ )
+ self.current_chunk += 1
+ self.total += 1
+ if self.current_chunk >= self.chunk_size:
+ self.commit()
+
+ def commit(self):
+ """
+ Manually commit and flush the batch indexing query
+ """
+ self.pipeline.execute()
+ self.current_chunk = 0
+
+ def __init__(self, client, index_name="idx"):
+ """
+ Create a new Client for the given index_name.
+ The default name is `idx`
+
+ If conn is not None, we employ an already existing redis connection
+ """
+ self.client = client
+ self.index_name = index_name
+ self.execute_command = client.execute_command
+ self.pipeline = client.pipeline
diff --git a/redis/commands/search/_util.py b/redis/commands/search/_util.py
new file mode 100644
index 0000000..b4ac19f
--- /dev/null
+++ b/redis/commands/search/_util.py
@@ -0,0 +1,10 @@
+import six
+
+
+def to_string(s):
+ if isinstance(s, six.string_types):
+ return s
+ elif isinstance(s, six.binary_type):
+ return s.decode("utf-8", "ignore")
+ else:
+ return s # Not a string we care about
diff --git a/redis/commands/search/aggregation.py b/redis/commands/search/aggregation.py
new file mode 100644
index 0000000..df912f8
--- /dev/null
+++ b/redis/commands/search/aggregation.py
@@ -0,0 +1,408 @@
+from six import string_types
+
+FIELDNAME = object()
+
+
+class Limit(object):
+ def __init__(self, offset=0, count=0):
+ self.offset = offset
+ self.count = count
+
+ def build_args(self):
+ if self.count:
+ return ["LIMIT", str(self.offset), str(self.count)]
+ else:
+ return []
+
+
+class Reducer(object):
+ """
+ Base reducer object for all reducers.
+
+ See the `redisearch.reducers` module for the actual reducers.
+ """
+
+ NAME = None
+
+ def __init__(self, *args):
+ self._args = args
+ self._field = None
+ self._alias = None
+
+ def alias(self, alias):
+ """
+ Set the alias for this reducer.
+
+ ### Parameters
+
+ - **alias**: The value of the alias for this reducer. If this is the
+ special value `aggregation.FIELDNAME` then this reducer will be
+ aliased using the same name as the field upon which it operates.
+ Note that using `FIELDNAME` is only possible on reducers which
+ operate on a single field value.
+
+ This method returns the `Reducer` object making it suitable for
+ chaining.
+ """
+ if alias is FIELDNAME:
+ if not self._field:
+ raise ValueError("Cannot use FIELDNAME alias with no field")
+ # Chop off initial '@'
+ alias = self._field[1:]
+ self._alias = alias
+ return self
+
+ @property
+ def args(self):
+ return self._args
+
+
+class SortDirection(object):
+ """
+ This special class is used to indicate sort direction.
+ """
+
+ DIRSTRING = None
+
+ def __init__(self, field):
+ self.field = field
+
+
+class Asc(SortDirection):
+ """
+ Indicate that the given field should be sorted in ascending order
+ """
+
+ DIRSTRING = "ASC"
+
+
+class Desc(SortDirection):
+ """
+ Indicate that the given field should be sorted in descending order
+ """
+
+ DIRSTRING = "DESC"
+
+
+class Group(object):
+ """
+ This object automatically created in the `AggregateRequest.group_by()`
+ """
+
+ def __init__(self, fields, reducers):
+ if not reducers:
+ raise ValueError("Need at least one reducer")
+
+ fields = [fields] if isinstance(fields, string_types) else fields
+ reducers = [reducers] if isinstance(reducers, Reducer) else reducers
+
+ self.fields = fields
+ self.reducers = reducers
+ self.limit = Limit()
+
+ def build_args(self):
+ ret = ["GROUPBY", str(len(self.fields))]
+ ret.extend(self.fields)
+ for reducer in self.reducers:
+ ret += ["REDUCE", reducer.NAME, str(len(reducer.args))]
+ ret.extend(reducer.args)
+ if reducer._alias is not None:
+ ret += ["AS", reducer._alias]
+ return ret
+
+
+class Projection(object):
+ """
+ This object automatically created in the `AggregateRequest.apply()`
+ """
+
+ def __init__(self, projector, alias=None):
+ self.alias = alias
+ self.projector = projector
+
+ def build_args(self):
+ ret = ["APPLY", self.projector]
+ if self.alias is not None:
+ ret += ["AS", self.alias]
+
+ return ret
+
+
+class SortBy(object):
+ """
+ This object automatically created in the `AggregateRequest.sort_by()`
+ """
+
+ def __init__(self, fields, max=0):
+ self.fields = fields
+ self.max = max
+
+ def build_args(self):
+ fields_args = []
+ for f in self.fields:
+ if isinstance(f, SortDirection):
+ fields_args += [f.field, f.DIRSTRING]
+ else:
+ fields_args += [f]
+
+ ret = ["SORTBY", str(len(fields_args))]
+ ret.extend(fields_args)
+ if self.max > 0:
+ ret += ["MAX", str(self.max)]
+
+ return ret
+
+
+class AggregateRequest(object):
+ """
+ Aggregation request which can be passed to `Client.aggregate`.
+ """
+
+ def __init__(self, query="*"):
+ """
+ Create an aggregation request. This request may then be passed to
+ `client.aggregate()`.
+
+ In order for the request to be usable, it must contain at least one
+ group.
+
+ - **query** Query string for filtering records.
+
+ All member methods (except `build_args()`)
+ return the object itself, making them useful for chaining.
+ """
+ self._query = query
+ self._aggregateplan = []
+ self._loadfields = []
+ self._limit = Limit()
+ self._max = 0
+ self._with_schema = False
+ self._verbatim = False
+ self._cursor = []
+
+ def load(self, *fields):
+ """
+ Indicate the fields to be returned in the response. These fields are
+ returned in addition to any others implicitly specified.
+
+ ### Parameters
+
+ - **fields**: One or more fields in the format of `@field`
+ """
+ self._loadfields.extend(fields)
+ return self
+
+ def group_by(self, fields, *reducers):
+ """
+ Specify by which fields to group the aggregation.
+
+ ### Parameters
+
+ - **fields**: Fields to group by. This can either be a single string,
+ or a list of strings. both cases, the field should be specified as
+ `@field`.
+ - **reducers**: One or more reducers. Reducers may be found in the
+ `aggregation` module.
+ """
+ group = Group(fields, reducers)
+ self._aggregateplan.extend(group.build_args())
+
+ return self
+
+ def apply(self, **kwexpr):
+ """
+ Specify one or more projection expressions to add to each result
+
+ ### Parameters
+
+ - **kwexpr**: One or more key-value pairs for a projection. The key is
+ the alias for the projection, and the value is the projection
+ expression itself, for example `apply(square_root="sqrt(@foo)")`
+ """
+ for alias, expr in kwexpr.items():
+ projection = Projection(expr, alias)
+ self._aggregateplan.extend(projection.build_args())
+
+ return self
+
+ def limit(self, offset, num):
+ """
+ Sets the limit for the most recent group or query.
+
+ If no group has been defined yet (via `group_by()`) then this sets
+ the limit for the initial pool of results from the query. Otherwise,
+ this limits the number of items operated on from the previous group.
+
+ Setting a limit on the initial search results may be useful when
+ attempting to execute an aggregation on a sample of a large data set.
+
+ ### Parameters
+
+ - **offset**: Result offset from which to begin paging
+ - **num**: Number of results to return
+
+
+ Example of sorting the initial results:
+
+ ```
+ AggregateRequest("@sale_amount:[10000, inf]")\
+ .limit(0, 10)\
+ .group_by("@state", r.count())
+ ```
+
+ Will only group by the states found in the first 10 results of the
+ query `@sale_amount:[10000, inf]`. On the other hand,
+
+ ```
+ AggregateRequest("@sale_amount:[10000, inf]")\
+ .limit(0, 1000)\
+ .group_by("@state", r.count()\
+ .limit(0, 10)
+ ```
+
+ Will group all the results matching the query, but only return the
+ first 10 groups.
+
+ If you only wish to return a *top-N* style query, consider using
+ `sort_by()` instead.
+
+ """
+ limit = Limit(offset, num)
+ self._limit = limit
+ return self
+
+ def sort_by(self, *fields, **kwargs):
+ """
+ Indicate how the results should be sorted. This can also be used for
+ *top-N* style queries
+
+ ### Parameters
+
+ - **fields**: The fields by which to sort. This can be either a single
+ field or a list of fields. If you wish to specify order, you can
+ use the `Asc` or `Desc` wrapper classes.
+ - **max**: Maximum number of results to return. This can be
+ used instead of `LIMIT` and is also faster.
+
+
+ Example of sorting by `foo` ascending and `bar` descending:
+
+ ```
+ sort_by(Asc("@foo"), Desc("@bar"))
+ ```
+
+ Return the top 10 customers:
+
+ ```
+ AggregateRequest()\
+ .group_by("@customer", r.sum("@paid").alias(FIELDNAME))\
+ .sort_by(Desc("@paid"), max=10)
+ ```
+ """
+ if isinstance(fields, (string_types, SortDirection)):
+ fields = [fields]
+
+ max = kwargs.get("max", 0)
+ sortby = SortBy(fields, max)
+
+ self._aggregateplan.extend(sortby.build_args())
+ return self
+
+ def filter(self, expressions):
+ """
+ Specify filter for post-query results using predicates relating to
+ values in the result set.
+
+ ### Parameters
+
+ - **fields**: Fields to group by. This can either be a single string,
+ or a list of strings.
+ """
+ if isinstance(expressions, string_types):
+ expressions = [expressions]
+
+ for expression in expressions:
+ self._aggregateplan.extend(["FILTER", expression])
+
+ return self
+
+ def with_schema(self):
+ """
+ If set, the `schema` property will contain a list of `[field, type]`
+ entries in the result object.
+ """
+ self._with_schema = True
+ return self
+
+ def verbatim(self):
+ self._verbatim = True
+ return self
+
+ def cursor(self, count=0, max_idle=0.0):
+ args = ["WITHCURSOR"]
+ if count:
+ args += ["COUNT", str(count)]
+ if max_idle:
+ args += ["MAXIDLE", str(max_idle * 1000)]
+ self._cursor = args
+ return self
+
+ def _limit_2_args(self, limit):
+ if limit[1]:
+ return ["LIMIT"] + [str(x) for x in limit]
+ else:
+ return []
+
+ def build_args(self):
+ # @foo:bar ...
+ ret = [self._query]
+
+ if self._with_schema:
+ ret.append("WITHSCHEMA")
+
+ if self._verbatim:
+ ret.append("VERBATIM")
+
+ if self._cursor:
+ ret += self._cursor
+
+ if self._loadfields:
+ ret.append("LOAD")
+ ret.append(str(len(self._loadfields)))
+ ret.extend(self._loadfields)
+
+ ret.extend(self._aggregateplan)
+
+ ret += self._limit.build_args()
+
+ return ret
+
+
+class Cursor(object):
+ def __init__(self, cid):
+ self.cid = cid
+ self.max_idle = 0
+ self.count = 0
+
+ def build_args(self):
+ args = [str(self.cid)]
+ if self.max_idle:
+ args += ["MAXIDLE", str(self.max_idle)]
+ if self.count:
+ args += ["COUNT", str(self.count)]
+ return args
+
+
+class AggregateResult(object):
+ def __init__(self, rows, cursor, schema):
+ self.rows = rows
+ self.cursor = cursor
+ self.schema = schema
+
+ def __repr__(self):
+ return "<{} at 0x{:x} Rows={}, Cursor={}>".format(
+ self.__class__.__name__,
+ id(self),
+ len(self.rows),
+ self.cursor.cid if self.cursor else -1,
+ )
diff --git a/redis/commands/search/commands.py b/redis/commands/search/commands.py
new file mode 100644
index 0000000..6074d29
--- /dev/null
+++ b/redis/commands/search/commands.py
@@ -0,0 +1,704 @@
+import itertools
+import time
+import six
+
+from .document import Document
+from .result import Result
+from .query import Query
+from ._util import to_string
+from .aggregation import AggregateRequest, AggregateResult, Cursor
+from .suggestion import SuggestionParser
+
+NUMERIC = "NUMERIC"
+
+CREATE_CMD = "FT.CREATE"
+ALTER_CMD = "FT.ALTER"
+SEARCH_CMD = "FT.SEARCH"
+ADD_CMD = "FT.ADD"
+ADDHASH_CMD = "FT.ADDHASH"
+DROP_CMD = "FT.DROP"
+EXPLAIN_CMD = "FT.EXPLAIN"
+DEL_CMD = "FT.DEL"
+AGGREGATE_CMD = "FT.AGGREGATE"
+CURSOR_CMD = "FT.CURSOR"
+SPELLCHECK_CMD = "FT.SPELLCHECK"
+DICT_ADD_CMD = "FT.DICTADD"
+DICT_DEL_CMD = "FT.DICTDEL"
+DICT_DUMP_CMD = "FT.DICTDUMP"
+GET_CMD = "FT.GET"
+MGET_CMD = "FT.MGET"
+CONFIG_CMD = "FT.CONFIG"
+TAGVALS_CMD = "FT.TAGVALS"
+ALIAS_ADD_CMD = "FT.ALIASADD"
+ALIAS_UPDATE_CMD = "FT.ALIASUPDATE"
+ALIAS_DEL_CMD = "FT.ALIASDEL"
+INFO_CMD = "FT.INFO"
+SUGADD_COMMAND = "FT.SUGADD"
+SUGDEL_COMMAND = "FT.SUGDEL"
+SUGLEN_COMMAND = "FT.SUGLEN"
+SUGGET_COMMAND = "FT.SUGGET"
+SYNUPDATE_CMD = "FT.SYNUPDATE"
+SYNDUMP_CMD = "FT.SYNDUMP"
+
+NOOFFSETS = "NOOFFSETS"
+NOFIELDS = "NOFIELDS"
+STOPWORDS = "STOPWORDS"
+WITHSCORES = "WITHSCORES"
+FUZZY = "FUZZY"
+WITHPAYLOADS = "WITHPAYLOADS"
+
+
+class SearchCommands:
+ """Search commands."""
+
+ def batch_indexer(self, chunk_size=100):
+ """
+ Create a new batch indexer from the client with a given chunk size
+ """
+ return self.BatchIndexer(self, chunk_size=chunk_size)
+
+ def create_index(
+ self,
+ fields,
+ no_term_offsets=False,
+ no_field_flags=False,
+ stopwords=None,
+ definition=None,
+ ):
+ """
+ Create the search index. The index must not already exist.
+
+ ### Parameters:
+
+ - **fields**: a list of TextField or NumericField objects
+ - **no_term_offsets**: If true, we will not save term offsets in
+ the index
+ - **no_field_flags**: If true, we will not save field flags that
+ allow searching in specific fields
+ - **stopwords**: If not None, we create the index with this custom
+ stopword list. The list can be empty
+ """
+
+ args = [CREATE_CMD, self.index_name]
+ if definition is not None:
+ args += definition.args
+ if no_term_offsets:
+ args.append(NOOFFSETS)
+ if no_field_flags:
+ args.append(NOFIELDS)
+ if stopwords is not None and isinstance(stopwords, (list, tuple, set)):
+ args += [STOPWORDS, len(stopwords)]
+ if len(stopwords) > 0:
+ args += list(stopwords)
+
+ args.append("SCHEMA")
+ try:
+ args += list(itertools.chain(*(f.redis_args() for f in fields)))
+ except TypeError:
+ args += fields.redis_args()
+
+ return self.execute_command(*args)
+
+ def alter_schema_add(self, fields):
+ """
+ Alter the existing search index by adding new fields. The index
+ must already exist.
+
+ ### Parameters:
+
+ - **fields**: a list of Field objects to add for the index
+ """
+
+ args = [ALTER_CMD, self.index_name, "SCHEMA", "ADD"]
+ try:
+ args += list(itertools.chain(*(f.redis_args() for f in fields)))
+ except TypeError:
+ args += fields.redis_args()
+
+ return self.execute_command(*args)
+
+ def drop_index(self, delete_documents=True):
+ """
+ Drop the index if it exists. Deprecated from RediSearch 2.0.
+
+ ### Parameters:
+
+ - **delete_documents**: If `True`, all documents will be deleted.
+ """
+ keep_str = "" if delete_documents else "KEEPDOCS"
+ return self.execute_command(DROP_CMD, self.index_name, keep_str)
+
+ def dropindex(self, delete_documents=False):
+ """
+ Drop the index if it exists.
+ Replaced `drop_index` in RediSearch 2.0.
+ Default behavior was changed to not delete the indexed documents.
+
+ ### Parameters:
+
+ - **delete_documents**: If `True`, all documents will be deleted.
+ """
+ keep_str = "" if delete_documents else "KEEPDOCS"
+ return self.execute_command(DROP_CMD, self.index_name, keep_str)
+
+ def _add_document(
+ self,
+ doc_id,
+ conn=None,
+ nosave=False,
+ score=1.0,
+ payload=None,
+ replace=False,
+ partial=False,
+ language=None,
+ no_create=False,
+ **fields
+ ):
+ """
+ Internal add_document used for both batch and single doc indexing
+ """
+ if conn is None:
+ conn = self.client
+
+ if partial or no_create:
+ replace = True
+
+ args = [ADD_CMD, self.index_name, doc_id, score]
+ if nosave:
+ args.append("NOSAVE")
+ if payload is not None:
+ args.append("PAYLOAD")
+ args.append(payload)
+ if replace:
+ args.append("REPLACE")
+ if partial:
+ args.append("PARTIAL")
+ if no_create:
+ args.append("NOCREATE")
+ if language:
+ args += ["LANGUAGE", language]
+ args.append("FIELDS")
+ args += list(itertools.chain(*fields.items()))
+ return conn.execute_command(*args)
+
+ def _add_document_hash(
+ self,
+ doc_id,
+ conn=None,
+ score=1.0,
+ language=None,
+ replace=False,
+ ):
+ """
+ Internal add_document_hash used for both batch and single doc indexing
+ """
+ if conn is None:
+ conn = self.client
+
+ args = [ADDHASH_CMD, self.index_name, doc_id, score]
+
+ if replace:
+ args.append("REPLACE")
+
+ if language:
+ args += ["LANGUAGE", language]
+
+ return conn.execute_command(*args)
+
+ def add_document(
+ self,
+ doc_id,
+ nosave=False,
+ score=1.0,
+ payload=None,
+ replace=False,
+ partial=False,
+ language=None,
+ no_create=False,
+ **fields
+ ):
+ """
+ Add a single document to the index.
+
+ ### Parameters
+
+ - **doc_id**: the id of the saved document.
+ - **nosave**: if set to true, we just index the document, and don't
+ save a copy of it. This means that searches will just
+ return ids.
+ - **score**: the document ranking, between 0.0 and 1.0
+ - **payload**: optional inner-index payload we can save for fast
+ i access in scoring functions
+ - **replace**: if True, and the document already is in the index,
+ we perform an update and reindex the document
+ - **partial**: if True, the fields specified will be added to the
+ existing document.
+ This has the added benefit that any fields specified
+ with `no_index`
+ will not be reindexed again. Implies `replace`
+ - **language**: Specify the language used for document tokenization.
+ - **no_create**: if True, the document is only updated and reindexed
+ if it already exists.
+ If the document does not exist, an error will be
+ returned. Implies `replace`
+ - **fields** kwargs dictionary of the document fields to be saved
+ and/or indexed.
+ NOTE: Geo points shoule be encoded as strings of "lon,lat"
+ """
+ return self._add_document(
+ doc_id,
+ conn=None,
+ nosave=nosave,
+ score=score,
+ payload=payload,
+ replace=replace,
+ partial=partial,
+ language=language,
+ no_create=no_create,
+ **fields
+ )
+
+ def add_document_hash(
+ self,
+ doc_id,
+ score=1.0,
+ language=None,
+ replace=False,
+ ):
+ """
+ Add a hash document to the index.
+
+ ### Parameters
+
+ - **doc_id**: the document's id. This has to be an existing HASH key
+ in Redis that will hold the fields the index needs.
+ - **score**: the document ranking, between 0.0 and 1.0
+ - **replace**: if True, and the document already is in the index, we
+ perform an update and reindex the document
+ - **language**: Specify the language used for document tokenization.
+ """
+ return self._add_document_hash(
+ doc_id,
+ conn=None,
+ score=score,
+ language=language,
+ replace=replace,
+ )
+
+ def delete_document(self, doc_id, conn=None, delete_actual_document=False):
+ """
+ Delete a document from index
+ Returns 1 if the document was deleted, 0 if not
+
+ ### Parameters
+
+ - **delete_actual_document**: if set to True, RediSearch also delete
+ the actual document if it is in the index
+ """
+ args = [DEL_CMD, self.index_name, doc_id]
+ if conn is None:
+ conn = self.client
+ if delete_actual_document:
+ args.append("DD")
+
+ return conn.execute_command(*args)
+
+ def load_document(self, id):
+ """
+ Load a single document by id
+ """
+ fields = self.client.hgetall(id)
+ if six.PY3:
+ f2 = {to_string(k): to_string(v) for k, v in fields.items()}
+ fields = f2
+
+ try:
+ del fields["id"]
+ except KeyError:
+ pass
+
+ return Document(id=id, **fields)
+
+ def get(self, *ids):
+ """
+ Returns the full contents of multiple documents.
+
+ ### Parameters
+
+ - **ids**: the ids of the saved documents.
+ """
+
+ return self.client.execute_command(MGET_CMD, self.index_name, *ids)
+
+ def info(self):
+ """
+ Get info an stats about the the current index, including the number of
+ documents, memory consumption, etc
+ """
+
+ res = self.client.execute_command(INFO_CMD, self.index_name)
+ it = six.moves.map(to_string, res)
+ return dict(six.moves.zip(it, it))
+
+ def _mk_query_args(self, query):
+ args = [self.index_name]
+
+ if isinstance(query, six.string_types):
+ # convert the query from a text to a query object
+ query = Query(query)
+ if not isinstance(query, Query):
+ raise ValueError("Bad query type %s" % type(query))
+
+ args += query.get_args()
+ return args, query
+
+ def search(self, query):
+ """
+ Search the index for a given query, and return a result of documents
+
+ ### Parameters
+
+ - **query**: the search query. Either a text for simple queries with
+ default parameters, or a Query object for complex queries.
+ See RediSearch's documentation on query format
+ """
+ args, query = self._mk_query_args(query)
+ st = time.time()
+ res = self.execute_command(SEARCH_CMD, *args)
+
+ return Result(
+ res,
+ not query._no_content,
+ duration=(time.time() - st) * 1000.0,
+ has_payload=query._with_payloads,
+ with_scores=query._with_scores,
+ )
+
+ def explain(self, query):
+ args, query_text = self._mk_query_args(query)
+ return self.execute_command(EXPLAIN_CMD, *args)
+
+ def aggregate(self, query):
+ """
+ Issue an aggregation query
+
+ ### Parameters
+
+ **query**: This can be either an `AggeregateRequest`, or a `Cursor`
+
+ An `AggregateResult` object is returned. You can access the rows from
+ its `rows` property, which will always yield the rows of the result.
+ """
+ if isinstance(query, AggregateRequest):
+ has_cursor = bool(query._cursor)
+ cmd = [AGGREGATE_CMD, self.index_name] + query.build_args()
+ elif isinstance(query, Cursor):
+ has_cursor = True
+ cmd = [CURSOR_CMD, "READ", self.index_name] + query.build_args()
+ else:
+ raise ValueError("Bad query", query)
+
+ raw = self.execute_command(*cmd)
+ if has_cursor:
+ if isinstance(query, Cursor):
+ query.cid = raw[1]
+ cursor = query
+ else:
+ cursor = Cursor(raw[1])
+ raw = raw[0]
+ else:
+ cursor = None
+
+ if isinstance(query, AggregateRequest) and query._with_schema:
+ schema = raw[0]
+ rows = raw[2:]
+ else:
+ schema = None
+ rows = raw[1:]
+
+ res = AggregateResult(rows, cursor, schema)
+ return res
+
+ def spellcheck(self, query, distance=None, include=None, exclude=None):
+ """
+ Issue a spellcheck query
+
+ ### Parameters
+
+ **query**: search query.
+ **distance***: the maximal Levenshtein distance for spelling
+ suggestions (default: 1, max: 4).
+ **include**: specifies an inclusion custom dictionary.
+ **exclude**: specifies an exclusion custom dictionary.
+ """
+ cmd = [SPELLCHECK_CMD, self.index_name, query]
+ if distance:
+ cmd.extend(["DISTANCE", distance])
+
+ if include:
+ cmd.extend(["TERMS", "INCLUDE", include])
+
+ if exclude:
+ cmd.extend(["TERMS", "EXCLUDE", exclude])
+
+ raw = self.execute_command(*cmd)
+
+ corrections = {}
+ if raw == 0:
+ return corrections
+
+ for _correction in raw:
+ if isinstance(_correction, six.integer_types) and _correction == 0:
+ continue
+
+ if len(_correction) != 3:
+ continue
+ if not _correction[2]:
+ continue
+ if not _correction[2][0]:
+ continue
+
+ # For spellcheck output
+ # 1) 1) "TERM"
+ # 2) "{term1}"
+ # 3) 1) 1) "{score1}"
+ # 2) "{suggestion1}"
+ # 2) 1) "{score2}"
+ # 2) "{suggestion2}"
+ #
+ # Following dictionary will be made
+ # corrections = {
+ # '{term1}': [
+ # {'score': '{score1}', 'suggestion': '{suggestion1}'},
+ # {'score': '{score2}', 'suggestion': '{suggestion2}'}
+ # ]
+ # }
+ corrections[_correction[1]] = [
+ {"score": _item[0], "suggestion": _item[1]}
+ for _item in _correction[2]
+ ]
+
+ return corrections
+
+ def dict_add(self, name, *terms):
+ """Adds terms to a dictionary.
+
+ ### Parameters
+
+ - **name**: Dictionary name.
+ - **terms**: List of items for adding to the dictionary.
+ """
+ cmd = [DICT_ADD_CMD, name]
+ cmd.extend(terms)
+ return self.execute_command(*cmd)
+
+ def dict_del(self, name, *terms):
+ """Deletes terms from a dictionary.
+
+ ### Parameters
+
+ - **name**: Dictionary name.
+ - **terms**: List of items for removing from the dictionary.
+ """
+ cmd = [DICT_DEL_CMD, name]
+ cmd.extend(terms)
+ return self.execute_command(*cmd)
+
+ def dict_dump(self, name):
+ """Dumps all terms in the given dictionary.
+
+ ### Parameters
+
+ - **name**: Dictionary name.
+ """
+ cmd = [DICT_DUMP_CMD, name]
+ return self.execute_command(*cmd)
+
+ def config_set(self, option, value):
+ """Set runtime configuration option.
+
+ ### Parameters
+
+ - **option**: the name of the configuration option.
+ - **value**: a value for the configuration option.
+ """
+ cmd = [CONFIG_CMD, "SET", option, value]
+ raw = self.execute_command(*cmd)
+ return raw == "OK"
+
+ def config_get(self, option):
+ """Get runtime configuration option value.
+
+ ### Parameters
+
+ - **option**: the name of the configuration option.
+ """
+ cmd = [CONFIG_CMD, "GET", option]
+ res = {}
+ raw = self.execute_command(*cmd)
+ if raw:
+ for kvs in raw:
+ res[kvs[0]] = kvs[1]
+ return res
+
+ def tagvals(self, tagfield):
+ """
+ Return a list of all possible tag values
+
+ ### Parameters
+
+ - **tagfield**: Tag field name
+ """
+
+ return self.execute_command(TAGVALS_CMD, self.index_name, tagfield)
+
+ def aliasadd(self, alias):
+ """
+ Alias a search index - will fail if alias already exists
+
+ ### Parameters
+
+ - **alias**: Name of the alias to create
+ """
+
+ return self.execute_command(ALIAS_ADD_CMD, alias, self.index_name)
+
+ def aliasupdate(self, alias):
+ """
+ Updates an alias - will fail if alias does not already exist
+
+ ### Parameters
+
+ - **alias**: Name of the alias to create
+ """
+
+ return self.execute_command(ALIAS_UPDATE_CMD, alias, self.index_name)
+
+ def aliasdel(self, alias):
+ """
+ Removes an alias to a search index
+
+ ### Parameters
+
+ - **alias**: Name of the alias to delete
+ """
+ return self.execute_command(ALIAS_DEL_CMD, alias)
+
+ def sugadd(self, key, *suggestions, **kwargs):
+ """
+ Add suggestion terms to the AutoCompleter engine. Each suggestion has
+ a score and string.
+ If kwargs["increment"] is true and the terms are already in the
+ server's dictionary, we increment their scores.
+ More information `here <https://oss.redis.com/redisearch/master/Commands/#ftsugadd>`_. # noqa
+ """
+ # If Transaction is not False it will MULTI/EXEC which will error
+ pipe = self.pipeline(transaction=False)
+ for sug in suggestions:
+ args = [SUGADD_COMMAND, key, sug.string, sug.score]
+ if kwargs.get("increment"):
+ args.append("INCR")
+ if sug.payload:
+ args.append("PAYLOAD")
+ args.append(sug.payload)
+
+ pipe.execute_command(*args)
+
+ return pipe.execute()[-1]
+
+ def suglen(self, key):
+ """
+ Return the number of entries in the AutoCompleter index.
+ More information `here <https://oss.redis.com/redisearch/master/Commands/#ftsuglen>`_. # noqa
+ """
+ return self.execute_command(SUGLEN_COMMAND, key)
+
+ def sugdel(self, key, string):
+ """
+ Delete a string from the AutoCompleter index.
+ Returns 1 if the string was found and deleted, 0 otherwise.
+ More information `here <https://oss.redis.com/redisearch/master/Commands/#ftsugdel>`_. # noqa
+ """
+ return self.execute_command(SUGDEL_COMMAND, key, string)
+
+ def sugget(
+ self, key, prefix, fuzzy=False, num=10, with_scores=False,
+ with_payloads=False
+ ):
+ """
+ Get a list of suggestions from the AutoCompleter, for a given prefix.
+ More information `here <https://oss.redis.com/redisearch/master/Commands/#ftsugget>`_. # noqa
+
+ Parameters:
+
+ prefix : str
+ The prefix we are searching. **Must be valid ascii or utf-8**
+ fuzzy : bool
+ If set to true, the prefix search is done in fuzzy mode.
+ **NOTE**: Running fuzzy searches on short (<3 letters) prefixes
+ can be very
+ slow, and even scan the entire index.
+ with_scores : bool
+ If set to true, we also return the (refactored) score of
+ each suggestion.
+ This is normally not needed, and is NOT the original score
+ inserted into the index.
+ with_payloads : bool
+ Return suggestion payloads
+ num : int
+ The maximum number of results we return. Note that we might
+ return less. The algorithm trims irrelevant suggestions.
+
+ Returns:
+
+ list:
+ A list of Suggestion objects. If with_scores was False, the
+ score of all suggestions is 1.
+ """
+ args = [SUGGET_COMMAND, key, prefix, "MAX", num]
+ if fuzzy:
+ args.append(FUZZY)
+ if with_scores:
+ args.append(WITHSCORES)
+ if with_payloads:
+ args.append(WITHPAYLOADS)
+
+ ret = self.execute_command(*args)
+ results = []
+ if not ret:
+ return results
+
+ parser = SuggestionParser(with_scores, with_payloads, ret)
+ return [s for s in parser]
+
+ def synupdate(self, groupid, skipinitial=False, *terms):
+ """
+ Updates a synonym group.
+ The command is used to create or update a synonym group with
+ additional terms.
+ Only documents which were indexed after the update will be affected.
+
+ Parameters:
+
+ groupid :
+ Synonym group id.
+ skipinitial : bool
+ If set to true, we do not scan and index.
+ terms :
+ The terms.
+ """
+ cmd = [SYNUPDATE_CMD, self.index_name, groupid]
+ if skipinitial:
+ cmd.extend(["SKIPINITIALSCAN"])
+ cmd.extend(terms)
+ return self.execute_command(*cmd)
+
+ def syndump(self):
+ """
+ Dumps the contents of a synonym group.
+
+ The command is used to dump the synonyms data structure.
+ Returns a list of synonym terms and their synonym group ids.
+ """
+ raw = self.execute_command(SYNDUMP_CMD, self.index_name)
+ return {raw[i]: raw[i + 1] for i in range(0, len(raw), 2)}
diff --git a/redis/commands/search/document.py b/redis/commands/search/document.py
new file mode 100644
index 0000000..26ede34
--- /dev/null
+++ b/redis/commands/search/document.py
@@ -0,0 +1,16 @@
+import six
+
+
+class Document(object):
+ """
+ Represents a single document in a result set
+ """
+
+ def __init__(self, id, payload=None, **fields):
+ self.id = id
+ self.payload = payload
+ for k, v in six.iteritems(fields):
+ setattr(self, k, v)
+
+ def __repr__(self):
+ return "Document %s" % self.__dict__
diff --git a/redis/commands/search/field.py b/redis/commands/search/field.py
new file mode 100644
index 0000000..45114a4
--- /dev/null
+++ b/redis/commands/search/field.py
@@ -0,0 +1,94 @@
+class Field(object):
+
+ NUMERIC = "NUMERIC"
+ TEXT = "TEXT"
+ WEIGHT = "WEIGHT"
+ GEO = "GEO"
+ TAG = "TAG"
+ SORTABLE = "SORTABLE"
+ NOINDEX = "NOINDEX"
+ AS = "AS"
+
+ def __init__(self, name, args=[], sortable=False,
+ no_index=False, as_name=None):
+ self.name = name
+ self.args = args
+ self.args_suffix = list()
+ self.as_name = as_name
+
+ if sortable:
+ self.args_suffix.append(Field.SORTABLE)
+ if no_index:
+ self.args_suffix.append(Field.NOINDEX)
+
+ if no_index and not sortable:
+ raise ValueError("Non-Sortable non-Indexable fields are ignored")
+
+ def append_arg(self, value):
+ self.args.append(value)
+
+ def redis_args(self):
+ args = [self.name]
+ if self.as_name:
+ args += [self.AS, self.as_name]
+ args += self.args
+ args += self.args_suffix
+ return args
+
+
+class TextField(Field):
+ """
+ TextField is used to define a text field in a schema definition
+ """
+
+ NOSTEM = "NOSTEM"
+ PHONETIC = "PHONETIC"
+
+ def __init__(
+ self, name, weight=1.0, no_stem=False, phonetic_matcher=None, **kwargs
+ ):
+ Field.__init__(self, name,
+ args=[Field.TEXT, Field.WEIGHT, weight], **kwargs)
+
+ if no_stem:
+ Field.append_arg(self, self.NOSTEM)
+ if phonetic_matcher and phonetic_matcher in [
+ "dm:en",
+ "dm:fr",
+ "dm:pt",
+ "dm:es",
+ ]:
+ Field.append_arg(self, self.PHONETIC)
+ Field.append_arg(self, phonetic_matcher)
+
+
+class NumericField(Field):
+ """
+ NumericField is used to define a numeric field in a schema definition
+ """
+
+ def __init__(self, name, **kwargs):
+ Field.__init__(self, name, args=[Field.NUMERIC], **kwargs)
+
+
+class GeoField(Field):
+ """
+ GeoField is used to define a geo-indexing field in a schema definition
+ """
+
+ def __init__(self, name, **kwargs):
+ Field.__init__(self, name, args=[Field.GEO], **kwargs)
+
+
+class TagField(Field):
+ """
+ TagField is a tag-indexing field with simpler compression and tokenization.
+ See http://redisearch.io/Tags/
+ """
+
+ SEPARATOR = "SEPARATOR"
+
+ def __init__(self, name, separator=",", **kwargs):
+ Field.__init__(
+ self, name, args=[Field.TAG, self.SEPARATOR, separator], **kwargs
+ )
diff --git a/redis/commands/search/indexDefinition.py b/redis/commands/search/indexDefinition.py
new file mode 100644
index 0000000..4fbc609
--- /dev/null
+++ b/redis/commands/search/indexDefinition.py
@@ -0,0 +1,80 @@
+from enum import Enum
+
+
+class IndexType(Enum):
+ """Enum of the currently supported index types."""
+
+ HASH = 1
+ JSON = 2
+
+
+class IndexDefinition(object):
+ """IndexDefinition is used to define a index definition for automatic
+ indexing on Hash or Json update."""
+
+ def __init__(
+ self,
+ prefix=[],
+ filter=None,
+ language_field=None,
+ language=None,
+ score_field=None,
+ score=1.0,
+ payload_field=None,
+ index_type=None,
+ ):
+ self.args = []
+ self._appendIndexType(index_type)
+ self._appendPrefix(prefix)
+ self._appendFilter(filter)
+ self._appendLanguage(language_field, language)
+ self._appendScore(score_field, score)
+ self._appendPayload(payload_field)
+
+ def _appendIndexType(self, index_type):
+ """Append `ON HASH` or `ON JSON` according to the enum."""
+ if index_type is IndexType.HASH:
+ self.args.extend(["ON", "HASH"])
+ elif index_type is IndexType.JSON:
+ self.args.extend(["ON", "JSON"])
+ elif index_type is not None:
+ raise RuntimeError("index_type must be one of {}".
+ format(list(IndexType)))
+
+ def _appendPrefix(self, prefix):
+ """Append PREFIX."""
+ if len(prefix) > 0:
+ self.args.append("PREFIX")
+ self.args.append(len(prefix))
+ for p in prefix:
+ self.args.append(p)
+
+ def _appendFilter(self, filter):
+ """Append FILTER."""
+ if filter is not None:
+ self.args.append("FILTER")
+ self.args.append(filter)
+
+ def _appendLanguage(self, language_field, language):
+ """Append LANGUAGE_FIELD and LANGUAGE."""
+ if language_field is not None:
+ self.args.append("LANGUAGE_FIELD")
+ self.args.append(language_field)
+ if language is not None:
+ self.args.append("LANGUAGE")
+ self.args.append(language)
+
+ def _appendScore(self, score_field, score):
+ """Append SCORE_FIELD and SCORE."""
+ if score_field is not None:
+ self.args.append("SCORE_FIELD")
+ self.args.append(score_field)
+ if score is not None:
+ self.args.append("SCORE")
+ self.args.append(score)
+
+ def _appendPayload(self, payload_field):
+ """Append PAYLOAD_FIELD."""
+ if payload_field is not None:
+ self.args.append("PAYLOAD_FIELD")
+ self.args.append(payload_field)
diff --git a/redis/commands/search/query.py b/redis/commands/search/query.py
new file mode 100644
index 0000000..e2db7a4
--- /dev/null
+++ b/redis/commands/search/query.py
@@ -0,0 +1,328 @@
+import six
+
+
+class Query(object):
+ """
+ Query is used to build complex queries that have more parameters than just
+ the query string. The query string is set in the constructor, and other
+ options have setter functions.
+
+ The setter functions return the query object, so they can be chained,
+ i.e. `Query("foo").verbatim().filter(...)` etc.
+ """
+
+ def __init__(self, query_string):
+ """
+ Create a new query object.
+ The query string is set in the constructor, and other options have
+ setter functions.
+ """
+
+ self._query_string = query_string
+ self._offset = 0
+ self._num = 10
+ self._no_content = False
+ self._no_stopwords = False
+ self._fields = None
+ self._verbatim = False
+ self._with_payloads = False
+ self._with_scores = False
+ self._scorer = False
+ self._filters = list()
+ self._ids = None
+ self._slop = -1
+ self._in_order = False
+ self._sortby = None
+ self._return_fields = []
+ self._summarize_fields = []
+ self._highlight_fields = []
+ self._language = None
+ self._expander = None
+
+ def query_string(self):
+ """Return the query string of this query only."""
+ return self._query_string
+
+ def limit_ids(self, *ids):
+ """Limit the results to a specific set of pre-known document
+ ids of any length."""
+ self._ids = ids
+ return self
+
+ def return_fields(self, *fields):
+ """Add fields to return fields."""
+ self._return_fields += fields
+ return self
+
+ def return_field(self, field, as_field=None):
+ """Add field to return fields (Optional: add 'AS' name
+ to the field)."""
+ self._return_fields.append(field)
+ if as_field is not None:
+ self._return_fields += ("AS", as_field)
+ return self
+
+ def _mk_field_list(self, fields):
+ if not fields:
+ return []
+ return \
+ [fields] if isinstance(fields, six.string_types) else list(fields)
+
+ def summarize(self, fields=None, context_len=None,
+ num_frags=None, sep=None):
+ """
+ Return an abridged format of the field, containing only the segments of
+ the field which contain the matching term(s).
+
+ If `fields` is specified, then only the mentioned fields are
+ summarized; otherwise all results are summarized.
+
+ Server side defaults are used for each option (except `fields`)
+ if not specified
+
+ - **fields** List of fields to summarize. All fields are summarized
+ if not specified
+ - **context_len** Amount of context to include with each fragment
+ - **num_frags** Number of fragments per document
+ - **sep** Separator string to separate fragments
+ """
+ args = ["SUMMARIZE"]
+ fields = self._mk_field_list(fields)
+ if fields:
+ args += ["FIELDS", str(len(fields))] + fields
+
+ if context_len is not None:
+ args += ["LEN", str(context_len)]
+ if num_frags is not None:
+ args += ["FRAGS", str(num_frags)]
+ if sep is not None:
+ args += ["SEPARATOR", sep]
+
+ self._summarize_fields = args
+ return self
+
+ def highlight(self, fields=None, tags=None):
+ """
+ Apply specified markup to matched term(s) within the returned field(s).
+
+ - **fields** If specified then only those mentioned fields are
+ highlighted, otherwise all fields are highlighted
+ - **tags** A list of two strings to surround the match.
+ """
+ args = ["HIGHLIGHT"]
+ fields = self._mk_field_list(fields)
+ if fields:
+ args += ["FIELDS", str(len(fields))] + fields
+ if tags:
+ args += ["TAGS"] + list(tags)
+
+ self._highlight_fields = args
+ return self
+
+ def language(self, language):
+ """
+ Analyze the query as being in the specified language.
+
+ :param language: The language (e.g. `chinese` or `english`)
+ """
+ self._language = language
+ return self
+
+ def slop(self, slop):
+ """Allow a maximum of N intervening non matched terms between
+ phrase terms (0 means exact phrase).
+ """
+ self._slop = slop
+ return self
+
+ def in_order(self):
+ """
+ Match only documents where the query terms appear in
+ the same order in the document.
+ i.e. for the query "hello world", we do not match "world hello"
+ """
+ self._in_order = True
+ return self
+
+ def scorer(self, scorer):
+ """
+ Use a different scoring function to evaluate document relevance.
+ Default is `TFIDF`.
+
+ :param scorer: The scoring function to use
+ (e.g. `TFIDF.DOCNORM` or `BM25`)
+ """
+ self._scorer = scorer
+ return self
+
+ def get_args(self):
+ """Format the redis arguments for this query and return them."""
+ args = [self._query_string]
+ args += self._get_args_tags()
+ args += self._summarize_fields + self._highlight_fields
+ args += ["LIMIT", self._offset, self._num]
+ return args
+
+ def _get_args_tags(self):
+ args = []
+ if self._no_content:
+ args.append("NOCONTENT")
+ if self._fields:
+ args.append("INFIELDS")
+ args.append(len(self._fields))
+ args += self._fields
+ if self._verbatim:
+ args.append("VERBATIM")
+ if self._no_stopwords:
+ args.append("NOSTOPWORDS")
+ if self._filters:
+ for flt in self._filters:
+ if not isinstance(flt, Filter):
+ raise AttributeError("Did not receive a Filter object.")
+ args += flt.args
+ if self._with_payloads:
+ args.append("WITHPAYLOADS")
+ if self._scorer:
+ args += ["SCORER", self._scorer]
+ if self._with_scores:
+ args.append("WITHSCORES")
+ if self._ids:
+ args.append("INKEYS")
+ args.append(len(self._ids))
+ args += self._ids
+ if self._slop >= 0:
+ args += ["SLOP", self._slop]
+ if self._in_order:
+ args.append("INORDER")
+ if self._return_fields:
+ args.append("RETURN")
+ args.append(len(self._return_fields))
+ args += self._return_fields
+ if self._sortby:
+ if not isinstance(self._sortby, SortbyField):
+ raise AttributeError("Did not receive a SortByField.")
+ args.append("SORTBY")
+ args += self._sortby.args
+ if self._language:
+ args += ["LANGUAGE", self._language]
+ if self._expander:
+ args += ["EXPANDER", self._expander]
+
+ return args
+
+ def paging(self, offset, num):
+ """
+ Set the paging for the query (defaults to 0..10).
+
+ - **offset**: Paging offset for the results. Defaults to 0
+ - **num**: How many results do we want
+ """
+ self._offset = offset
+ self._num = num
+ return self
+
+ def verbatim(self):
+ """Set the query to be verbatim, i.e. use no query expansion
+ or stemming.
+ """
+ self._verbatim = True
+ return self
+
+ def no_content(self):
+ """Set the query to only return ids and not the document content."""
+ self._no_content = True
+ return self
+
+ def no_stopwords(self):
+ """
+ Prevent the query from being filtered for stopwords.
+ Only useful in very big queries that you are certain contain
+ no stopwords.
+ """
+ self._no_stopwords = True
+ return self
+
+ def with_payloads(self):
+ """Ask the engine to return document payloads."""
+ self._with_payloads = True
+ return self
+
+ def with_scores(self):
+ """Ask the engine to return document search scores."""
+ self._with_scores = True
+ return self
+
+ def limit_fields(self, *fields):
+ """
+ Limit the search to specific TEXT fields only.
+
+ - **fields**: A list of strings, case sensitive field names
+ from the defined schema.
+ """
+ self._fields = fields
+ return self
+
+ def add_filter(self, flt):
+ """
+ Add a numeric or geo filter to the query.
+ **Currently only one of each filter is supported by the engine**
+
+ - **flt**: A NumericFilter or GeoFilter object, used on a
+ corresponding field
+ """
+
+ self._filters.append(flt)
+ return self
+
+ def sort_by(self, field, asc=True):
+ """
+ Add a sortby field to the query.
+
+ - **field** - the name of the field to sort by
+ - **asc** - when `True`, sorting will be done in asceding order
+ """
+ self._sortby = SortbyField(field, asc)
+ return self
+
+ def expander(self, expander):
+ """
+ Add a expander field to the query.
+
+ - **expander** - the name of the expander
+ """
+ self._expander = expander
+ return self
+
+
+class Filter(object):
+ def __init__(self, keyword, field, *args):
+ self.args = [keyword, field] + list(args)
+
+
+class NumericFilter(Filter):
+ INF = "+inf"
+ NEG_INF = "-inf"
+
+ def __init__(self, field, minval, maxval, minExclusive=False,
+ maxExclusive=False):
+ args = [
+ minval if not minExclusive else "({}".format(minval),
+ maxval if not maxExclusive else "({}".format(maxval),
+ ]
+
+ Filter.__init__(self, "FILTER", field, *args)
+
+
+class GeoFilter(Filter):
+ METERS = "m"
+ KILOMETERS = "km"
+ FEET = "ft"
+ MILES = "mi"
+
+ def __init__(self, field, lon, lat, radius, unit=KILOMETERS):
+ Filter.__init__(self, "GEOFILTER", field, lon, lat, radius, unit)
+
+
+class SortbyField(object):
+ def __init__(self, field, asc=True):
+ self.args = [field, "ASC" if asc else "DESC"]
diff --git a/redis/commands/search/querystring.py b/redis/commands/search/querystring.py
new file mode 100644
index 0000000..f5f59b7
--- /dev/null
+++ b/redis/commands/search/querystring.py
@@ -0,0 +1,324 @@
+from six import string_types, integer_types
+
+
+def tags(*t):
+ """
+ Indicate that the values should be matched to a tag field
+
+ ### Parameters
+
+ - **t**: Tags to search for
+ """
+ if not t:
+ raise ValueError("At least one tag must be specified")
+ return TagValue(*t)
+
+
+def between(a, b, inclusive_min=True, inclusive_max=True):
+ """
+ Indicate that value is a numeric range
+ """
+ return RangeValue(a, b, inclusive_min=inclusive_min,
+ inclusive_max=inclusive_max)
+
+
+def equal(n):
+ """
+ Match a numeric value
+ """
+ return between(n, n)
+
+
+def lt(n):
+ """
+ Match any value less than n
+ """
+ return between(None, n, inclusive_max=False)
+
+
+def le(n):
+ """
+ Match any value less or equal to n
+ """
+ return between(None, n, inclusive_max=True)
+
+
+def gt(n):
+ """
+ Match any value greater than n
+ """
+ return between(n, None, inclusive_min=False)
+
+
+def ge(n):
+ """
+ Match any value greater or equal to n
+ """
+ return between(n, None, inclusive_min=True)
+
+
+def geo(lat, lon, radius, unit="km"):
+ """
+ Indicate that value is a geo region
+ """
+ return GeoValue(lat, lon, radius, unit)
+
+
+class Value(object):
+ @property
+ def combinable(self):
+ """
+ Whether this type of value may be combined with other values
+ for the same field. This makes the filter potentially more efficient
+ """
+ return False
+
+ @staticmethod
+ def make_value(v):
+ """
+ Convert an object to a value, if it is not a value already
+ """
+ if isinstance(v, Value):
+ return v
+ return ScalarValue(v)
+
+ def to_string(self):
+ raise NotImplementedError()
+
+ def __str__(self):
+ return self.to_string()
+
+
+class RangeValue(Value):
+ combinable = False
+
+ def __init__(self, a, b, inclusive_min=False, inclusive_max=False):
+ if a is None:
+ a = "-inf"
+ if b is None:
+ b = "inf"
+ self.range = [str(a), str(b)]
+ self.inclusive_min = inclusive_min
+ self.inclusive_max = inclusive_max
+
+ def to_string(self):
+ return "[{1}{0[0]} {2}{0[1]}]".format(
+ self.range,
+ "(" if not self.inclusive_min else "",
+ "(" if not self.inclusive_max else "",
+ )
+
+
+class ScalarValue(Value):
+ combinable = True
+
+ def __init__(self, v):
+ self.v = str(v)
+
+ def to_string(self):
+ return self.v
+
+
+class TagValue(Value):
+ combinable = False
+
+ def __init__(self, *tags):
+ self.tags = tags
+
+ def to_string(self):
+ return "{" + " | ".join(str(t) for t in self.tags) + "}"
+
+
+class GeoValue(Value):
+ def __init__(self, lon, lat, radius, unit="km"):
+ self.lon = lon
+ self.lat = lat
+ self.radius = radius
+ self.unit = unit
+
+
+class Node(object):
+ def __init__(self, *children, **kwparams):
+ """
+ Create a node
+
+ ### Parameters
+
+ - **children**: One or more sub-conditions. These can be additional
+ `intersect`, `disjunct`, `union`, `optional`, or any other `Node`
+ type.
+
+ The semantics of multiple conditions are dependent on the type of
+ query. For an `intersection` node, this amounts to a logical AND,
+ for a `union` node, this amounts to a logical `OR`.
+
+ - **kwparams**: key-value parameters. Each key is the name of a field,
+ and the value should be a field value. This can be one of the
+ following:
+
+ - Simple string (for text field matches)
+ - value returned by one of the helper functions
+ - list of either a string or a value
+
+
+ ### Examples
+
+ Field `num` should be between 1 and 10
+ ```
+ intersect(num=between(1, 10)
+ ```
+
+ Name can either be `bob` or `john`
+
+ ```
+ union(name=("bob", "john"))
+ ```
+
+ Don't select countries in Israel, Japan, or US
+
+ ```
+ disjunct_union(country=("il", "jp", "us"))
+ ```
+ """
+
+ self.params = []
+
+ kvparams = {}
+ for k, v in kwparams.items():
+ curvals = kvparams.setdefault(k, [])
+ if isinstance(v, (string_types, integer_types, float)):
+ curvals.append(Value.make_value(v))
+ elif isinstance(v, Value):
+ curvals.append(v)
+ else:
+ curvals.extend(Value.make_value(subv) for subv in v)
+
+ self.params += [Node.to_node(p) for p in children]
+
+ for k, v in kvparams.items():
+ self.params.extend(self.join_fields(k, v))
+
+ def join_fields(self, key, vals):
+ if len(vals) == 1:
+ return [BaseNode("@{}:{}".format(key, vals[0].to_string()))]
+ if not vals[0].combinable:
+ return [BaseNode("@{}:{}".format(key,
+ v.to_string())) for v in vals]
+ s = BaseNode(
+ "@{}:({})".format(key,
+ self.JOINSTR.join(v.to_string() for v in vals))
+ )
+ return [s]
+
+ @classmethod
+ def to_node(cls, obj): # noqa
+ if isinstance(obj, Node):
+ return obj
+ return BaseNode(obj)
+
+ @property
+ def JOINSTR(self):
+ raise NotImplementedError()
+
+ def to_string(self, with_parens=None):
+ with_parens = self._should_use_paren(with_parens)
+ pre, post = ("(", ")") if with_parens else ("", "")
+ return "{}{}{}".format(
+ pre, self.JOINSTR.join(n.to_string() for n in self.params), post
+ )
+
+ def _should_use_paren(self, optval):
+ if optval is not None:
+ return optval
+ return len(self.params) > 1
+
+ def __str__(self):
+ return self.to_string()
+
+
+class BaseNode(Node):
+ def __init__(self, s):
+ super(BaseNode, self).__init__()
+ self.s = str(s)
+
+ def to_string(self, with_parens=None):
+ return self.s
+
+
+class IntersectNode(Node):
+ """
+ Create an intersection node. All children need to be satisfied in order for
+ this node to evaluate as true
+ """
+
+ JOINSTR = " "
+
+
+class UnionNode(Node):
+ """
+ Create a union node. Any of the children need to be satisfied in order for
+ this node to evaluate as true
+ """
+
+ JOINSTR = "|"
+
+
+class DisjunctNode(IntersectNode):
+ """
+ Create a disjunct node. In order for this node to be true, all of its
+ children must evaluate to false
+ """
+
+ def to_string(self, with_parens=None):
+ with_parens = self._should_use_paren(with_parens)
+ ret = super(DisjunctNode, self).to_string(with_parens=False)
+ if with_parens:
+ return "(-" + ret + ")"
+ else:
+ return "-" + ret
+
+
+class DistjunctUnion(DisjunctNode):
+ """
+ This node is true if *all* of its children are false. This is equivalent to
+ ```
+ disjunct(union(...))
+ ```
+ """
+
+ JOINSTR = "|"
+
+
+class OptionalNode(IntersectNode):
+ """
+ Create an optional node. If this nodes evaluates to true, then the document
+ will be rated higher in score/rank.
+ """
+
+ def to_string(self, with_parens=None):
+ with_parens = self._should_use_paren(with_parens)
+ ret = super(OptionalNode, self).to_string(with_parens=False)
+ if with_parens:
+ return "(~" + ret + ")"
+ else:
+ return "~" + ret
+
+
+def intersect(*args, **kwargs):
+ return IntersectNode(*args, **kwargs)
+
+
+def union(*args, **kwargs):
+ return UnionNode(*args, **kwargs)
+
+
+def disjunct(*args, **kwargs):
+ return DisjunctNode(*args, **kwargs)
+
+
+def disjunct_union(*args, **kwargs):
+ return DistjunctUnion(*args, **kwargs)
+
+
+def querystring(*args, **kwargs):
+ return intersect(*args, **kwargs).to_string()
diff --git a/redis/commands/search/reducers.py b/redis/commands/search/reducers.py
new file mode 100644
index 0000000..6cbbf2f
--- /dev/null
+++ b/redis/commands/search/reducers.py
@@ -0,0 +1,178 @@
+from .aggregation import Reducer, SortDirection
+
+
+class FieldOnlyReducer(Reducer):
+ def __init__(self, field):
+ super(FieldOnlyReducer, self).__init__(field)
+ self._field = field
+
+
+class count(Reducer):
+ """
+ Counts the number of results in the group
+ """
+
+ NAME = "COUNT"
+
+ def __init__(self):
+ super(count, self).__init__()
+
+
+class sum(FieldOnlyReducer):
+ """
+ Calculates the sum of all the values in the given fields within the group
+ """
+
+ NAME = "SUM"
+
+ def __init__(self, field):
+ super(sum, self).__init__(field)
+
+
+class min(FieldOnlyReducer):
+ """
+ Calculates the smallest value in the given field within the group
+ """
+
+ NAME = "MIN"
+
+ def __init__(self, field):
+ super(min, self).__init__(field)
+
+
+class max(FieldOnlyReducer):
+ """
+ Calculates the largest value in the given field within the group
+ """
+
+ NAME = "MAX"
+
+ def __init__(self, field):
+ super(max, self).__init__(field)
+
+
+class avg(FieldOnlyReducer):
+ """
+ Calculates the mean value in the given field within the group
+ """
+
+ NAME = "AVG"
+
+ def __init__(self, field):
+ super(avg, self).__init__(field)
+
+
+class tolist(FieldOnlyReducer):
+ """
+ Returns all the matched properties in a list
+ """
+
+ NAME = "TOLIST"
+
+ def __init__(self, field):
+ super(tolist, self).__init__(field)
+
+
+class count_distinct(FieldOnlyReducer):
+ """
+ Calculate the number of distinct values contained in all the results in
+ the group for the given field
+ """
+
+ NAME = "COUNT_DISTINCT"
+
+ def __init__(self, field):
+ super(count_distinct, self).__init__(field)
+
+
+class count_distinctish(FieldOnlyReducer):
+ """
+ Calculate the number of distinct values contained in all the results in the
+ group for the given field. This uses a faster algorithm than
+ `count_distinct` but is less accurate
+ """
+
+ NAME = "COUNT_DISTINCTISH"
+
+
+class quantile(Reducer):
+ """
+ Return the value for the nth percentile within the range of values for the
+ field within the group.
+ """
+
+ NAME = "QUANTILE"
+
+ def __init__(self, field, pct):
+ super(quantile, self).__init__(field, str(pct))
+ self._field = field
+
+
+class stddev(FieldOnlyReducer):
+ """
+ Return the standard deviation for the values within the group
+ """
+
+ NAME = "STDDEV"
+
+ def __init__(self, field):
+ super(stddev, self).__init__(field)
+
+
+class first_value(Reducer):
+ """
+ Selects the first value within the group according to sorting parameters
+ """
+
+ NAME = "FIRST_VALUE"
+
+ def __init__(self, field, *byfields):
+ """
+ Selects the first value of the given field within the group.
+
+ ### Parameter
+
+ - **field**: Source field used for the value
+ - **byfields**: How to sort the results. This can be either the
+ *class* of `aggregation.Asc` or `aggregation.Desc` in which
+ case the field `field` is also used as the sort input.
+
+ `byfields` can also be one or more *instances* of `Asc` or `Desc`
+ indicating the sort order for these fields
+ """
+
+ fieldstrs = []
+ if (
+ len(byfields) == 1
+ and isinstance(byfields[0], type)
+ and issubclass(byfields[0], SortDirection)
+ ):
+ byfields = [byfields[0](field)]
+
+ for f in byfields:
+ fieldstrs += [f.field, f.DIRSTRING]
+
+ args = [field]
+ if fieldstrs:
+ args += ["BY"] + fieldstrs
+ super(first_value, self).__init__(*args)
+ self._field = field
+
+
+class random_sample(Reducer):
+ """
+ Returns a random sample of items from the dataset, from the given property
+ """
+
+ NAME = "RANDOM_SAMPLE"
+
+ def __init__(self, field, size):
+ """
+ ### Parameter
+
+ **field**: Field to sample from
+ **size**: Return this many items (can be less)
+ """
+ args = [field, str(size)]
+ super(random_sample, self).__init__(*args)
+ self._field = field
diff --git a/redis/commands/search/result.py b/redis/commands/search/result.py
new file mode 100644
index 0000000..afc83f8
--- /dev/null
+++ b/redis/commands/search/result.py
@@ -0,0 +1,75 @@
+from six.moves import xrange, zip as izip
+
+from .document import Document
+from ._util import to_string
+
+
+class Result(object):
+ """
+ Represents the result of a search query, and has an array of Document
+ objects
+ """
+
+ def __init__(
+ self, res, hascontent, duration=0, has_payload=False, with_scores=False
+ ):
+ """
+ - **snippets**: An optional dictionary of the form
+ {field: snippet_size} for snippet formatting
+ """
+
+ self.total = res[0]
+ self.duration = duration
+ self.docs = []
+
+ step = 1
+ if hascontent:
+ step = step + 1
+ if has_payload:
+ step = step + 1
+ if with_scores:
+ step = step + 1
+
+ offset = 2 if with_scores else 1
+
+ for i in xrange(1, len(res), step):
+ id = to_string(res[i])
+ payload = to_string(res[i + offset]) if has_payload else None
+ # fields_offset = 2 if has_payload else 1
+ fields_offset = offset + 1 if has_payload else offset
+ score = float(res[i + 1]) if with_scores else None
+
+ fields = {}
+ if hascontent:
+ fields = (
+ dict(
+ dict(
+ izip(
+ map(to_string, res[i + fields_offset][::2]),
+ map(to_string, res[i + fields_offset][1::2]),
+ )
+ )
+ )
+ if hascontent
+ else {}
+ )
+ try:
+ del fields["id"]
+ except KeyError:
+ pass
+
+ try:
+ fields["json"] = fields["$"]
+ del fields["$"]
+ except KeyError:
+ pass
+
+ doc = (
+ Document(id, score=score, payload=payload, **fields)
+ if with_scores
+ else Document(id, payload=payload, **fields)
+ )
+ self.docs.append(doc)
+
+ def __repr__(self):
+ return "Result{%d total, docs: %s}" % (self.total, self.docs)
diff --git a/redis/commands/search/suggestion.py b/redis/commands/search/suggestion.py
new file mode 100644
index 0000000..550c514
--- /dev/null
+++ b/redis/commands/search/suggestion.py
@@ -0,0 +1,54 @@
+from six.moves import xrange
+from ._util import to_string
+
+
+class Suggestion(object):
+ """
+ Represents a single suggestion being sent or returned from the
+ autocomplete server
+ """
+
+ def __init__(self, string, score=1.0, payload=None):
+ self.string = to_string(string)
+ self.payload = to_string(payload)
+ self.score = score
+
+ def __repr__(self):
+ return self.string
+
+
+class SuggestionParser(object):
+ """
+ Internal class used to parse results from the `SUGGET` command.
+ This needs to consume either 1, 2, or 3 values at a time from
+ the return value depending on what objects were requested
+ """
+
+ def __init__(self, with_scores, with_payloads, ret):
+ self.with_scores = with_scores
+ self.with_payloads = with_payloads
+
+ if with_scores and with_payloads:
+ self.sugsize = 3
+ self._scoreidx = 1
+ self._payloadidx = 2
+ elif with_scores:
+ self.sugsize = 2
+ self._scoreidx = 1
+ elif with_payloads:
+ self.sugsize = 2
+ self._payloadidx = 1
+ else:
+ self.sugsize = 1
+ self._scoreidx = -1
+
+ self._sugs = ret
+
+ def __iter__(self):
+ for i in xrange(0, len(self._sugs), self.sugsize):
+ ss = self._sugs[i]
+ score = float(self._sugs[i + self._scoreidx]) \
+ if self.with_scores else 1.0
+ payload = self._sugs[i + self._payloadidx] \
+ if self.with_payloads else None
+ yield Suggestion(ss, score, payload)
diff --git a/tasks.py b/tasks.py
index 15e983b..aa965c6 100644
--- a/tasks.py
+++ b/tasks.py
@@ -17,7 +17,6 @@ def devenv(c):
cmd = 'tox -e devenv'
for d in dockers:
cmd += " --docker-dont-stop={}".format(d)
- print("Running: {}".format(cmd))
run(cmd)
diff --git a/tests/conftest.py b/tests/conftest.py
index 9ca429d..47188df 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -13,6 +13,8 @@ REDIS_INFO = {}
default_redis_url = "redis://localhost:6379/9"
default_redismod_url = "redis://localhost:36379/9"
+default_redismod_url = "redis://localhost:36379"
+
def pytest_addoption(parser):
parser.addoption('--redis-url', default=default_redis_url,
@@ -85,6 +87,7 @@ def skip_ifmodversion_lt(min_version: str, module_name: str):
def _get_client(cls, request, single_connection_client=True, flushdb=True,
+ from_url=None,
**kwargs):
"""
Helper for fixtures or tests that need a Redis client
@@ -93,7 +96,10 @@ def _get_client(cls, request, single_connection_client=True, flushdb=True,
ConnectionPool.from_url, keyword arguments to this function override
values specified in the URL.
"""
- redis_url = request.config.getoption("--redis-url")
+ if from_url is None:
+ redis_url = request.config.getoption("--redis-url")
+ else:
+ redis_url = from_url
url_options = parse_url(redis_url)
url_options.update(kwargs)
pool = redis.ConnectionPool(**url_options)
@@ -115,9 +121,12 @@ def _get_client(cls, request, single_connection_client=True, flushdb=True,
return client
+# specifically set to the zero database, because creating
+# an index on db != 0 raises a ResponseError in redis
@pytest.fixture()
-def modclient(request, port=36379, **kwargs):
- with _get_client(redis.Redis, request, port=port, **kwargs) as client:
+def modclient(request, **kwargs):
+ rmurl = request.config.getoption('--redismod-url')
+ with _get_client(redis.Redis, request, from_url=rmurl, **kwargs) as client:
yield client
diff --git a/tests/test_json.py b/tests/test_json.py
index 96675f1..83fbf28 100644
--- a/tests/test_json.py
+++ b/tests/test_json.py
@@ -10,7 +10,7 @@ def client(modclient):
return modclient
-@pytest.mark.json
+@pytest.mark.redismod
def test_json_setbinarykey(client):
d = {"hello": "world", b"some": "value"}
with pytest.raises(TypeError):
@@ -18,7 +18,7 @@ def test_json_setbinarykey(client):
assert client.json().set("somekey", Path.rootPath(), d, decode_keys=True)
-@pytest.mark.json
+@pytest.mark.redismod
def test_json_setgetdeleteforget(client):
assert client.json().set("foo", Path.rootPath(), "bar")
assert client.json().get("foo") == "bar"
@@ -28,13 +28,13 @@ def test_json_setgetdeleteforget(client):
assert client.exists("foo") == 0
-@pytest.mark.json
+@pytest.mark.redismod
def test_justaget(client):
client.json().set("foo", Path.rootPath(), "bar")
assert client.json().get("foo") == "bar"
-@pytest.mark.json
+@pytest.mark.redismod
def test_json_get_jset(client):
assert client.json().set("foo", Path.rootPath(), "bar")
assert "bar" == client.json().get("foo")
@@ -43,7 +43,7 @@ def test_json_get_jset(client):
assert client.exists("foo") == 0
-@pytest.mark.json
+@pytest.mark.redismod
def test_nonascii_setgetdelete(client):
assert client.json().set("notascii", Path.rootPath(),
"hyvää-élève") is True
@@ -52,7 +52,7 @@ def test_nonascii_setgetdelete(client):
assert client.exists("notascii") == 0
-@pytest.mark.json
+@pytest.mark.redismod
def test_jsonsetexistentialmodifiersshouldsucceed(client):
obj = {"foo": "bar"}
assert client.json().set("obj", Path.rootPath(), obj)
@@ -70,7 +70,7 @@ def test_jsonsetexistentialmodifiersshouldsucceed(client):
client.json().set("obj", Path("foo"), "baz", nx=True, xx=True)
-@pytest.mark.json
+@pytest.mark.redismod
def test_mgetshouldsucceed(client):
client.json().set("1", Path.rootPath(), 1)
client.json().set("2", Path.rootPath(), 2)
@@ -79,7 +79,7 @@ def test_mgetshouldsucceed(client):
assert e == r
-@pytest.mark.json
+@pytest.mark.redismod
@skip_ifmodversion_lt("99.99.99", "ReJSON") # todo: update after the release
def test_clearShouldSucceed(client):
client.json().set("arr", Path.rootPath(), [0, 1, 2, 3, 4])
@@ -87,13 +87,13 @@ def test_clearShouldSucceed(client):
assert [] == client.json().get("arr")
-@pytest.mark.json
+@pytest.mark.redismod
def test_typeshouldsucceed(client):
client.json().set("1", Path.rootPath(), 1)
assert b"integer" == client.json().type("1")
-@pytest.mark.json
+@pytest.mark.redismod
def test_numincrbyshouldsucceed(client):
client.json().set("num", Path.rootPath(), 1)
assert 2 == client.json().numincrby("num", Path.rootPath(), 1)
@@ -101,7 +101,7 @@ def test_numincrbyshouldsucceed(client):
assert 1.25 == client.json().numincrby("num", Path.rootPath(), -1.25)
-@pytest.mark.json
+@pytest.mark.redismod
def test_nummultbyshouldsucceed(client):
client.json().set("num", Path.rootPath(), 1)
assert 2 == client.json().nummultby("num", Path.rootPath(), 2)
@@ -109,7 +109,7 @@ def test_nummultbyshouldsucceed(client):
assert 2.5 == client.json().nummultby("num", Path.rootPath(), 0.5)
-@pytest.mark.json
+@pytest.mark.redismod
@skip_ifmodversion_lt("99.99.99", "ReJSON") # todo: update after the release
def test_toggleShouldSucceed(client):
client.json().set("bool", Path.rootPath(), False)
@@ -121,20 +121,20 @@ def test_toggleShouldSucceed(client):
client.json().toggle("num", Path.rootPath())
-@pytest.mark.json
+@pytest.mark.redismod
def test_strappendshouldsucceed(client):
client.json().set("str", Path.rootPath(), "foo")
assert 6 == client.json().strappend("str", "bar", Path.rootPath())
assert "foobar" == client.json().get("str", Path.rootPath())
-@pytest.mark.json
+@pytest.mark.redismod
def test_debug(client):
client.json().set("str", Path.rootPath(), "foo")
assert 24 == client.json().debug("str", Path.rootPath())
-@pytest.mark.json
+@pytest.mark.redismod
def test_strlenshouldsucceed(client):
client.json().set("str", Path.rootPath(), "foo")
assert 3 == client.json().strlen("str", Path.rootPath())
@@ -142,7 +142,7 @@ def test_strlenshouldsucceed(client):
assert 6 == client.json().strlen("str", Path.rootPath())
-@pytest.mark.json
+@pytest.mark.redismod
def test_arrappendshouldsucceed(client):
client.json().set("arr", Path.rootPath(), [1])
assert 2 == client.json().arrappend("arr", Path.rootPath(), 2)
@@ -150,14 +150,14 @@ def test_arrappendshouldsucceed(client):
assert 7 == client.json().arrappend("arr", Path.rootPath(), *[5, 6, 7])
-@pytest.mark.json
+@pytest.mark.redismod
def testArrIndexShouldSucceed(client):
client.json().set("arr", Path.rootPath(), [0, 1, 2, 3, 4])
assert 1 == client.json().arrindex("arr", Path.rootPath(), 1)
assert -1 == client.json().arrindex("arr", Path.rootPath(), 1, 2)
-@pytest.mark.json
+@pytest.mark.redismod
def test_arrinsertshouldsucceed(client):
client.json().set("arr", Path.rootPath(), [0, 4])
assert 5 - -client.json().arrinsert(
@@ -173,13 +173,13 @@ def test_arrinsertshouldsucceed(client):
assert [0, 1, 2, 3, 4] == client.json().get("arr")
-@pytest.mark.json
+@pytest.mark.redismod
def test_arrlenshouldsucceed(client):
client.json().set("arr", Path.rootPath(), [0, 1, 2, 3, 4])
assert 5 == client.json().arrlen("arr", Path.rootPath())
-@pytest.mark.json
+@pytest.mark.redismod
def test_arrpopshouldsucceed(client):
client.json().set("arr", Path.rootPath(), [0, 1, 2, 3, 4])
assert 4 == client.json().arrpop("arr", Path.rootPath(), 4)
@@ -189,14 +189,14 @@ def test_arrpopshouldsucceed(client):
assert [1] == client.json().get("arr")
-@pytest.mark.json
+@pytest.mark.redismod
def test_arrtrimshouldsucceed(client):
client.json().set("arr", Path.rootPath(), [0, 1, 2, 3, 4])
assert 3 == client.json().arrtrim("arr", Path.rootPath(), 1, 3)
assert [1, 2, 3] == client.json().get("arr")
-@pytest.mark.json
+@pytest.mark.redismod
def test_respshouldsucceed(client):
obj = {"foo": "bar", "baz": 1, "qaz": True}
client.json().set("obj", Path.rootPath(), obj)
@@ -205,7 +205,7 @@ def test_respshouldsucceed(client):
assert client.json().resp("obj", Path("qaz"))
-@pytest.mark.json
+@pytest.mark.redismod
def test_objkeysshouldsucceed(client):
obj = {"foo": "bar", "baz": "qaz"}
client.json().set("obj", Path.rootPath(), obj)
@@ -216,7 +216,7 @@ def test_objkeysshouldsucceed(client):
assert exp == keys
-@pytest.mark.json
+@pytest.mark.redismod
def test_objlenshouldsucceed(client):
obj = {"foo": "bar", "baz": "qaz"}
client.json().set("obj", Path.rootPath(), obj)
@@ -224,7 +224,7 @@ def test_objlenshouldsucceed(client):
# @pytest.mark.pipeline
-# @pytest.mark.json
+# @pytest.mark.redismod
# def test_pipelineshouldsucceed(client):
# p = client.json().pipeline()
# p.set("foo", Path.rootPath(), "bar")
diff --git a/tests/test_search.py b/tests/test_search.py
new file mode 100644
index 0000000..926b5ff
--- /dev/null
+++ b/tests/test_search.py
@@ -0,0 +1,1219 @@
+import pytest
+import redis
+import bz2
+import csv
+import time
+import os
+
+from io import TextIOWrapper
+from .conftest import skip_ifmodversion_lt, default_redismod_url
+from redis import Redis
+
+import redis.commands.search
+from redis.commands.json.path import Path
+from redis.commands.search import Search
+from redis.commands.search.field import (
+ GeoField,
+ NumericField,
+ TagField,
+ TextField
+)
+from redis.commands.search.query import (
+ GeoFilter,
+ NumericFilter,
+ Query
+)
+from redis.commands.search.result import Result
+from redis.commands.search.indexDefinition import IndexDefinition, IndexType
+from redis.commands.search.suggestion import Suggestion
+import redis.commands.search.aggregation as aggregations
+import redis.commands.search.reducers as reducers
+
+WILL_PLAY_TEXT = (
+ os.path.abspath(
+ os.path.join(
+ os.path.dirname(__file__),
+ "testdata",
+ "will_play_text.csv.bz2"
+ )
+ )
+)
+
+TITLES_CSV = (
+ os.path.abspath(
+ os.path.join(
+ os.path.dirname(__file__),
+ "testdata",
+ "titles.csv"
+ )
+ )
+)
+
+
+def waitForIndex(env, idx, timeout=None):
+ delay = 0.1
+ while True:
+ res = env.execute_command("ft.info", idx)
+ try:
+ res.index("indexing")
+ except ValueError:
+ break
+
+ if int(res[res.index("indexing") + 1]) == 0:
+ break
+
+ time.sleep(delay)
+ if timeout is not None:
+ timeout -= delay
+ if timeout <= 0:
+ break
+
+
+def getClient():
+ """
+ Gets a client client attached to an index name which is ready to be
+ created
+ """
+ rc = Redis.from_url(default_redismod_url, decode_responses=True)
+ return rc
+
+
+def createIndex(client, num_docs=100, definition=None):
+ try:
+ client.create_index(
+ (TextField("play", weight=5.0),
+ TextField("txt"),
+ NumericField("chapter")),
+ definition=definition,
+ )
+ except redis.ResponseError:
+ client.dropindex(delete_documents=True)
+ return createIndex(client, num_docs=num_docs, definition=definition)
+
+ chapters = {}
+ bzfp = TextIOWrapper(bz2.BZ2File(WILL_PLAY_TEXT), encoding="utf8")
+
+ r = csv.reader(bzfp, delimiter=";")
+ for n, line in enumerate(r):
+
+ play, chapter, _, text = \
+ line[1], line[2], line[4], line[5]
+
+ key = "{}:{}".format(play, chapter).lower()
+ d = chapters.setdefault(key, {})
+ d["play"] = play
+ d["txt"] = d.get("txt", "") + " " + text
+ d["chapter"] = int(chapter or 0)
+ if len(chapters) == num_docs:
+ break
+
+ indexer = client.batch_indexer(chunk_size=50)
+ assert isinstance(indexer, Search.BatchIndexer)
+ assert 50 == indexer.chunk_size
+
+ for key, doc in chapters.items():
+ indexer.add_document(key, **doc)
+ indexer.commit()
+
+
+# override the default module client, search requires both db=0, and text
+@pytest.fixture
+def modclient():
+ return Redis.from_url(default_redismod_url, db=0, decode_responses=True)
+
+
+@pytest.fixture
+def client(modclient):
+ modclient.flushdb()
+ return modclient
+
+
+@pytest.mark.redismod
+def test_client(client):
+ num_docs = 500
+ createIndex(client.ft(), num_docs=num_docs)
+ waitForIndex(client, "idx")
+ # verify info
+ info = client.ft().info()
+ for k in [
+ "index_name",
+ "index_options",
+ "attributes",
+ "num_docs",
+ "max_doc_id",
+ "num_terms",
+ "num_records",
+ "inverted_sz_mb",
+ "offset_vectors_sz_mb",
+ "doc_table_size_mb",
+ "key_table_size_mb",
+ "records_per_doc_avg",
+ "bytes_per_record_avg",
+ "offsets_per_term_avg",
+ "offset_bits_per_record_avg",
+ ]:
+ assert k in info
+
+ assert client.ft().index_name == info["index_name"]
+ assert num_docs == int(info["num_docs"])
+
+ res = client.ft().search("henry iv")
+ assert isinstance(res, Result)
+ assert 225 == res.total
+ assert 10 == len(res.docs)
+ assert res.duration > 0
+
+ for doc in res.docs:
+ assert doc.id
+ assert doc.play == "Henry IV"
+ assert len(doc.txt) > 0
+
+ # test no content
+ res = client.ft().search(Query("king").no_content())
+ assert 194 == res.total
+ assert 10 == len(res.docs)
+ for doc in res.docs:
+ assert "txt" not in doc.__dict__
+ assert "play" not in doc.__dict__
+
+ # test verbatim vs no verbatim
+ total = client.ft().search(Query("kings").no_content()).total
+ vtotal = client.ft().search(Query("kings").no_content().verbatim()).total
+ assert total > vtotal
+
+ # test in fields
+ txt_total = (
+ client.ft().search(
+ Query("henry").no_content().limit_fields("txt")).total
+ )
+ play_total = (
+ client.ft().search(
+ Query("henry").no_content().limit_fields("play")).total
+ )
+ both_total = (
+ client.ft()
+ .search(Query("henry").no_content().limit_fields("play", "txt"))
+ .total
+ )
+ assert 129 == txt_total
+ assert 494 == play_total
+ assert 494 == both_total
+
+ # test load_document
+ doc = client.ft().load_document("henry vi part 3:62")
+ assert doc is not None
+ assert "henry vi part 3:62" == doc.id
+ assert doc.play == "Henry VI Part 3"
+ assert len(doc.txt) > 0
+
+ # test in-keys
+ ids = [x.id for x in client.ft().search(Query("henry")).docs]
+ assert 10 == len(ids)
+ subset = ids[:5]
+ docs = client.ft().search(Query("henry").limit_ids(*subset))
+ assert len(subset) == docs.total
+ ids = [x.id for x in docs.docs]
+ assert set(ids) == set(subset)
+
+ # test slop and in order
+ assert 193 == client.ft().search(Query("henry king")).total
+ assert 3 == client.ft().search(
+ Query("henry king").slop(0).in_order()).total
+ assert 52 == client.ft().search(
+ Query("king henry").slop(0).in_order()).total
+ assert 53 == client.ft().search(Query("henry king").slop(0)).total
+ assert 167 == client.ft().search(Query("henry king").slop(100)).total
+
+ # test delete document
+ client.ft().add_document("doc-5ghs2", play="Death of a Salesman")
+ res = client.ft().search(Query("death of a salesman"))
+ assert 1 == res.total
+
+ assert 1 == client.ft().delete_document("doc-5ghs2")
+ res = client.ft().search(Query("death of a salesman"))
+ assert 0 == res.total
+ assert 0 == client.ft().delete_document("doc-5ghs2")
+
+ client.ft().add_document("doc-5ghs2", play="Death of a Salesman")
+ res = client.ft().search(Query("death of a salesman"))
+ assert 1 == res.total
+ client.ft().delete_document("doc-5ghs2")
+
+
+@pytest.mark.redismod
+@skip_ifmodversion_lt("2.2.0", "search")
+def test_payloads(client):
+ client.ft().create_index((TextField("txt"),))
+
+ client.ft().add_document("doc1", payload="foo baz", txt="foo bar")
+ client.ft().add_document("doc2", txt="foo bar")
+
+ q = Query("foo bar").with_payloads()
+ res = client.ft().search(q)
+ assert 2 == res.total
+ assert "doc1" == res.docs[0].id
+ assert "doc2" == res.docs[1].id
+ assert "foo baz" == res.docs[0].payload
+ assert res.docs[1].payload is None
+
+
+@pytest.mark.redismod
+def test_scores(client):
+ client.ft().create_index((TextField("txt"),))
+
+ client.ft().add_document("doc1", txt="foo baz")
+ client.ft().add_document("doc2", txt="foo bar")
+
+ q = Query("foo ~bar").with_scores()
+ res = client.ft().search(q)
+ assert 2 == res.total
+ assert "doc2" == res.docs[0].id
+ assert 3.0 == res.docs[0].score
+ assert "doc1" == res.docs[1].id
+ # todo: enable once new RS version is tagged
+ # self.assertEqual(0.2, res.docs[1].score)
+
+
+@pytest.mark.redismod
+def test_replace(client):
+ client.ft().create_index((TextField("txt"),))
+
+ client.ft().add_document("doc1", txt="foo bar")
+ client.ft().add_document("doc2", txt="foo bar")
+ waitForIndex(client, "idx")
+
+ res = client.ft().search("foo bar")
+ assert 2 == res.total
+ client.ft().add_document(
+ "doc1",
+ replace=True,
+ txt="this is a replaced doc"
+ )
+
+ res = client.ft().search("foo bar")
+ assert 1 == res.total
+ assert "doc2" == res.docs[0].id
+
+ res = client.ft().search("replaced doc")
+ assert 1 == res.total
+ assert "doc1" == res.docs[0].id
+
+
+@pytest.mark.redismod
+def test_stopwords(client):
+ client.ft().create_index(
+ (TextField("txt"),),
+ stopwords=["foo", "bar", "baz"]
+ )
+ client.ft().add_document("doc1", txt="foo bar")
+ client.ft().add_document("doc2", txt="hello world")
+ waitForIndex(client, "idx")
+
+ q1 = Query("foo bar").no_content()
+ q2 = Query("foo bar hello world").no_content()
+ res1, res2 = client.ft().search(q1), client.ft().search(q2)
+ assert 0 == res1.total
+ assert 1 == res2.total
+
+
+@pytest.mark.redismod
+def test_filters(client):
+ client.ft().create_index(
+ (TextField("txt"),
+ NumericField("num"),
+ GeoField("loc"))
+ )
+ client.ft().add_document(
+ "doc1",
+ txt="foo bar",
+ num=3.141,
+ loc="-0.441,51.458"
+ )
+ client.ft().add_document("doc2", txt="foo baz", num=2, loc="-0.1,51.2")
+
+ waitForIndex(client, "idx")
+ # Test numerical filter
+ q1 = Query("foo").add_filter(NumericFilter("num", 0, 2)).no_content()
+ q2 = (
+ Query("foo")
+ .add_filter(
+ NumericFilter("num", 2, NumericFilter.INF, minExclusive=True))
+ .no_content()
+ )
+ res1, res2 = client.ft().search(q1), client.ft().search(q2)
+
+ assert 1 == res1.total
+ assert 1 == res2.total
+ assert "doc2" == res1.docs[0].id
+ assert "doc1" == res2.docs[0].id
+
+ # Test geo filter
+ q1 = Query("foo").add_filter(
+ GeoFilter("loc", -0.44, 51.45, 10)).no_content()
+ q2 = Query("foo").add_filter(
+ GeoFilter("loc", -0.44, 51.45, 100)).no_content()
+ res1, res2 = client.ft().search(q1), client.ft().search(q2)
+
+ assert 1 == res1.total
+ assert 2 == res2.total
+ assert "doc1" == res1.docs[0].id
+
+ # Sort results, after RDB reload order may change
+ res = [res2.docs[0].id, res2.docs[1].id]
+ res.sort()
+ assert ["doc1", "doc2"] == res
+
+
+@pytest.mark.redismod
+def test_payloads_with_no_content(client):
+ client.ft().create_index((TextField("txt"),))
+ client.ft().add_document("doc1", payload="foo baz", txt="foo bar")
+ client.ft().add_document("doc2", payload="foo baz2", txt="foo bar")
+
+ q = Query("foo bar").with_payloads().no_content()
+ res = client.ft().search(q)
+ assert 2 == len(res.docs)
+
+
+@pytest.mark.redismod
+def test_sort_by(client):
+ client.ft().create_index(
+ (TextField("txt"),
+ NumericField("num", sortable=True))
+ )
+ client.ft().add_document("doc1", txt="foo bar", num=1)
+ client.ft().add_document("doc2", txt="foo baz", num=2)
+ client.ft().add_document("doc3", txt="foo qux", num=3)
+
+ # Test sort
+ q1 = Query("foo").sort_by("num", asc=True).no_content()
+ q2 = Query("foo").sort_by("num", asc=False).no_content()
+ res1, res2 = client.ft().search(q1), client.ft().search(q2)
+
+ assert 3 == res1.total
+ assert "doc1" == res1.docs[0].id
+ assert "doc2" == res1.docs[1].id
+ assert "doc3" == res1.docs[2].id
+ assert 3 == res2.total
+ assert "doc1" == res2.docs[2].id
+ assert "doc2" == res2.docs[1].id
+ assert "doc3" == res2.docs[0].id
+
+
+@pytest.mark.redismod
+@skip_ifmodversion_lt("2.0.0", "search")
+def test_drop_index():
+ """
+ Ensure the index gets dropped by data remains by default
+ """
+ for x in range(20):
+ for keep_docs in [[True, {}], [False, {"name": "haveit"}]]:
+ idx = "HaveIt"
+ index = getClient()
+ index.hset("index:haveit", mapping={"name": "haveit"})
+ idef = IndexDefinition(prefix=["index:"])
+ index.ft(idx).create_index((TextField("name"),), definition=idef)
+ waitForIndex(index, idx)
+ index.ft(idx).dropindex(delete_documents=keep_docs[0])
+ i = index.hgetall("index:haveit")
+ assert i == keep_docs[1]
+
+
+@pytest.mark.redismod
+def test_example(client):
+ # Creating the index definition and schema
+ client.ft().create_index(
+ (TextField("title", weight=5.0),
+ TextField("body"))
+ )
+
+ # Indexing a document
+ client.ft().add_document(
+ "doc1",
+ title="RediSearch",
+ body="Redisearch impements a search engine on top of redis",
+ )
+
+ # Searching with complex parameters:
+ q = Query("search engine").verbatim().no_content().paging(0, 5)
+
+ res = client.ft().search(q)
+ assert res is not None
+
+
+@pytest.mark.redismod
+def test_auto_complete(client):
+ n = 0
+ with open(TITLES_CSV) as f:
+ cr = csv.reader(f)
+
+ for row in cr:
+ n += 1
+ term, score = row[0], float(row[1])
+ assert n == client.ft().sugadd("ac", Suggestion(term, score=score))
+
+ assert n == client.ft().suglen("ac")
+ ret = client.ft().sugget("ac", "bad", with_scores=True)
+ assert 2 == len(ret)
+ assert "badger" == ret[0].string
+ assert isinstance(ret[0].score, float)
+ assert 1.0 != ret[0].score
+ assert "badalte rishtey" == ret[1].string
+ assert isinstance(ret[1].score, float)
+ assert 1.0 != ret[1].score
+
+ ret = client.ft().sugget("ac", "bad", fuzzy=True, num=10)
+ assert 10 == len(ret)
+ assert 1.0 == ret[0].score
+ strs = {x.string for x in ret}
+
+ for sug in strs:
+ assert 1 == client.ft().sugdel("ac", sug)
+ # make sure a second delete returns 0
+ for sug in strs:
+ assert 0 == client.ft().sugdel("ac", sug)
+
+ # make sure they were actually deleted
+ ret2 = client.ft().sugget("ac", "bad", fuzzy=True, num=10)
+ for sug in ret2:
+ assert sug.string not in strs
+
+ # Test with payload
+ client.ft().sugadd("ac", Suggestion("pay1", payload="pl1"))
+ client.ft().sugadd("ac", Suggestion("pay2", payload="pl2"))
+ client.ft().sugadd("ac", Suggestion("pay3", payload="pl3"))
+
+ sugs = client.ft().sugget(
+ "ac",
+ "pay",
+ with_payloads=True,
+ with_scores=True
+ )
+ assert 3 == len(sugs)
+ for sug in sugs:
+ assert sug.payload
+ assert sug.payload.startswith("pl")
+
+
+@pytest.mark.redismod
+def test_no_index(client):
+ client.ft().create_index(
+ (
+ TextField("field"),
+ TextField("text", no_index=True, sortable=True),
+ NumericField("numeric", no_index=True, sortable=True),
+ GeoField("geo", no_index=True, sortable=True),
+ TagField("tag", no_index=True, sortable=True),
+ )
+ )
+
+ client.ft().add_document(
+ "doc1", field="aaa", text="1", numeric="1", geo="1,1", tag="1"
+ )
+ client.ft().add_document(
+ "doc2", field="aab", text="2", numeric="2", geo="2,2", tag="2"
+ )
+ waitForIndex(client, "idx")
+
+ res = client.ft().search(Query("@text:aa*"))
+ assert 0 == res.total
+
+ res = client.ft().search(Query("@field:aa*"))
+ assert 2 == res.total
+
+ res = client.ft().search(Query("*").sort_by("text", asc=False))
+ assert 2 == res.total
+ assert "doc2" == res.docs[0].id
+
+ res = client.ft().search(Query("*").sort_by("text", asc=True))
+ assert "doc1" == res.docs[0].id
+
+ res = client.ft().search(Query("*").sort_by("numeric", asc=True))
+ assert "doc1" == res.docs[0].id
+
+ res = client.ft().search(Query("*").sort_by("geo", asc=True))
+ assert "doc1" == res.docs[0].id
+
+ res = client.ft().search(Query("*").sort_by("tag", asc=True))
+ assert "doc1" == res.docs[0].id
+
+ # Ensure exception is raised for non-indexable, non-sortable fields
+ with pytest.raises(Exception):
+ TextField("name", no_index=True, sortable=False)
+ with pytest.raises(Exception):
+ NumericField("name", no_index=True, sortable=False)
+ with pytest.raises(Exception):
+ GeoField("name", no_index=True, sortable=False)
+ with pytest.raises(Exception):
+ TagField("name", no_index=True, sortable=False)
+
+
+@pytest.mark.redismod
+def test_partial(client):
+ client.ft().create_index(
+ (TextField("f1"),
+ TextField("f2"),
+ TextField("f3"))
+ )
+ client.ft().add_document("doc1", f1="f1_val", f2="f2_val")
+ client.ft().add_document("doc2", f1="f1_val", f2="f2_val")
+ client.ft().add_document("doc1", f3="f3_val", partial=True)
+ client.ft().add_document("doc2", f3="f3_val", replace=True)
+ waitForIndex(client, "idx")
+
+ # Search for f3 value. All documents should have it
+ res = client.ft().search("@f3:f3_val")
+ assert 2 == res.total
+
+ # Only the document updated with PARTIAL should still have f1 and f2 values
+ res = client.ft().search("@f3:f3_val @f2:f2_val @f1:f1_val")
+ assert 1 == res.total
+
+
+@pytest.mark.redismod
+def test_no_create(client):
+ client.ft().create_index(
+ (TextField("f1"),
+ TextField("f2"),
+ TextField("f3"))
+ )
+ client.ft().add_document("doc1", f1="f1_val", f2="f2_val")
+ client.ft().add_document("doc2", f1="f1_val", f2="f2_val")
+ client.ft().add_document("doc1", f3="f3_val", no_create=True)
+ client.ft().add_document("doc2", f3="f3_val", no_create=True, partial=True)
+ waitForIndex(client, "idx")
+
+ # Search for f3 value. All documents should have it
+ res = client.ft().search("@f3:f3_val")
+ assert 2 == res.total
+
+ # Only the document updated with PARTIAL should still have f1 and f2 values
+ res = client.ft().search("@f3:f3_val @f2:f2_val @f1:f1_val")
+ assert 1 == res.total
+
+ with pytest.raises(redis.ResponseError):
+ client.ft().add_document(
+ "doc3",
+ f2="f2_val",
+ f3="f3_val",
+ no_create=True
+ )
+
+
+@pytest.mark.redismod
+def test_explain(client):
+ client.ft().create_index(
+ (TextField("f1"),
+ TextField("f2"),
+ TextField("f3"))
+ )
+ res = client.ft().explain("@f3:f3_val @f2:f2_val @f1:f1_val")
+ assert res
+
+
+@pytest.mark.redismod
+def test_summarize(client):
+ createIndex(client.ft())
+ waitForIndex(client, "idx")
+
+ q = Query("king henry").paging(0, 1)
+ q.highlight(fields=("play", "txt"), tags=("<b>", "</b>"))
+ q.summarize("txt")
+
+ doc = sorted(client.ft().search(q).docs)[0]
+ assert "<b>Henry</b> IV" == doc.play
+ assert (
+ "ACT I SCENE I. London. The palace. Enter <b>KING</b> <b>HENRY</b>, LORD JOHN OF LANCASTER, the EARL of WESTMORELAND, SIR... " # noqa
+ == doc.txt
+ )
+
+ q = Query("king henry").paging(0, 1).summarize().highlight()
+
+ doc = sorted(client.ft().search(q).docs)[0]
+ assert "<b>Henry</b> ... " == doc.play
+ assert (
+ "ACT I SCENE I. London. The palace. Enter <b>KING</b> <b>HENRY</b>, LORD JOHN OF LANCASTER, the EARL of WESTMORELAND, SIR... " # noqa
+ == doc.txt
+ )
+
+
+@pytest.mark.redismod
+@skip_ifmodversion_lt("2.0.0", "search")
+def test_alias():
+ index1 = getClient()
+ index2 = getClient()
+
+ index1.hset("index1:lonestar", mapping={"name": "lonestar"})
+ index2.hset("index2:yogurt", mapping={"name": "yogurt"})
+
+ if os.environ.get("GITHUB_WORKFLOW", None) is not None:
+ time.sleep(2)
+ else:
+ time.sleep(5)
+
+ def1 = IndexDefinition(prefix=["index1:"], score_field="name")
+ def2 = IndexDefinition(prefix=["index2:"], score_field="name")
+
+ ftindex1 = index1.ft("testAlias")
+ ftindex2 = index1.ft("testAlias2")
+ ftindex1.create_index((TextField("name"),), definition=def1)
+ ftindex2.create_index((TextField("name"),), definition=def2)
+
+ # CI is slower
+ try:
+ res = ftindex1.search("*").docs[0]
+ except IndexError:
+ time.sleep(5)
+ res = ftindex1.search("*").docs[0]
+ assert "index1:lonestar" == res.id
+
+ # create alias and check for results
+ ftindex1.aliasadd("spaceballs")
+ alias_client = getClient().ft("spaceballs")
+ res = alias_client.search("*").docs[0]
+ assert "index1:lonestar" == res.id
+
+ # Throw an exception when trying to add an alias that already exists
+ with pytest.raises(Exception):
+ ftindex2.aliasadd("spaceballs")
+
+ # update alias and ensure new results
+ ftindex2.aliasupdate("spaceballs")
+ alias_client2 = getClient().ft("spaceballs")
+ res = alias_client2.search("*").docs[0]
+ assert "index2:yogurt" == res.id
+
+ ftindex2.aliasdel("spaceballs")
+ with pytest.raises(Exception):
+ alias_client2.search("*").docs[0]
+
+
+@pytest.mark.redismod
+def test_alias_basic():
+ # Creating a client with one index
+ getClient().flushdb()
+ index1 = getClient().ft("testAlias")
+
+ index1.create_index((TextField("txt"),))
+ index1.add_document("doc1", txt="text goes here")
+
+ index2 = getClient().ft("testAlias2")
+ index2.create_index((TextField("txt"),))
+ index2.add_document("doc2", txt="text goes here")
+
+ # add the actual alias and check
+ index1.aliasadd("myalias")
+ alias_client = getClient().ft("myalias")
+ res = sorted(alias_client.search("*").docs, key=lambda x: x.id)
+ assert "doc1" == res[0].id
+
+ # Throw an exception when trying to add an alias that already exists
+ with pytest.raises(Exception):
+ index2.aliasadd("myalias")
+
+ # update the alias and ensure we get doc2
+ index2.aliasupdate("myalias")
+ alias_client2 = getClient().ft("myalias")
+ res = sorted(alias_client2.search("*").docs, key=lambda x: x.id)
+ assert "doc1" == res[0].id
+
+ # delete the alias and expect an error if we try to query again
+ index2.aliasdel("myalias")
+ with pytest.raises(Exception):
+ _ = alias_client2.search("*").docs[0]
+
+
+@pytest.mark.redismod
+def test_tags(client):
+ client.ft().create_index((TextField("txt"), TagField("tags")))
+ tags = "foo,foo bar,hello;world"
+ tags2 = "soba,ramen"
+
+ client.ft().add_document("doc1", txt="fooz barz", tags=tags)
+ client.ft().add_document("doc2", txt="noodles", tags=tags2)
+ waitForIndex(client, "idx")
+
+ q = Query("@tags:{foo}")
+ res = client.ft().search(q)
+ assert 1 == res.total
+
+ q = Query("@tags:{foo bar}")
+ res = client.ft().search(q)
+ assert 1 == res.total
+
+ q = Query("@tags:{foo\\ bar}")
+ res = client.ft().search(q)
+ assert 1 == res.total
+
+ q = Query("@tags:{hello\\;world}")
+ res = client.ft().search(q)
+ assert 1 == res.total
+
+ q2 = client.ft().tagvals("tags")
+ assert (tags.split(",") + tags2.split(",")).sort() == q2.sort()
+
+
+@pytest.mark.redismod
+def test_textfield_sortable_nostem(client):
+ # Creating the index definition with sortable and no_stem
+ client.ft().create_index((TextField("txt", sortable=True, no_stem=True),))
+
+ # Now get the index info to confirm its contents
+ response = client.ft().info()
+ assert "SORTABLE" in response["attributes"][0]
+ assert "NOSTEM" in response["attributes"][0]
+
+
+@pytest.mark.redismod
+def test_alter_schema_add(client):
+ # Creating the index definition and schema
+ client.ft().create_index(TextField("title"))
+
+ # Using alter to add a field
+ client.ft().alter_schema_add(TextField("body"))
+
+ # Indexing a document
+ client.ft().add_document(
+ "doc1", title="MyTitle", body="Some content only in the body"
+ )
+
+ # Searching with parameter only in the body (the added field)
+ q = Query("only in the body")
+
+ # Ensure we find the result searching on the added body field
+ res = client.ft().search(q)
+ assert 1 == res.total
+
+
+@pytest.mark.redismod
+def test_spell_check(client):
+ client.ft().create_index((TextField("f1"), TextField("f2")))
+
+ client.ft().add_document(
+ "doc1",
+ f1="some valid content",
+ f2="this is sample text"
+ )
+ client.ft().add_document("doc2", f1="very important", f2="lorem ipsum")
+ waitForIndex(client, "idx")
+
+ # test spellcheck
+ res = client.ft().spellcheck("impornant")
+ assert "important" == res["impornant"][0]["suggestion"]
+
+ res = client.ft().spellcheck("contnt")
+ assert "content" == res["contnt"][0]["suggestion"]
+
+ # test spellcheck with Levenshtein distance
+ res = client.ft().spellcheck("vlis")
+ assert res == {}
+ res = client.ft().spellcheck("vlis", distance=2)
+ assert "valid" == res["vlis"][0]["suggestion"]
+
+ # test spellcheck include
+ client.ft().dict_add("dict", "lore", "lorem", "lorm")
+ res = client.ft().spellcheck("lorm", include="dict")
+ assert len(res["lorm"]) == 3
+ assert (
+ res["lorm"][0]["suggestion"],
+ res["lorm"][1]["suggestion"],
+ res["lorm"][2]["suggestion"],
+ ) == ("lorem", "lore", "lorm")
+ assert (res["lorm"][0]["score"], res["lorm"][1]["score"]) == ("0.5", "0")
+
+ # test spellcheck exclude
+ res = client.ft().spellcheck("lorm", exclude="dict")
+ assert res == {}
+
+
+@pytest.mark.redismod
+def test_dict_operations(client):
+ client.ft().create_index((TextField("f1"), TextField("f2")))
+ # Add three items
+ res = client.ft().dict_add("custom_dict", "item1", "item2", "item3")
+ assert 3 == res
+
+ # Remove one item
+ res = client.ft().dict_del("custom_dict", "item2")
+ assert 1 == res
+
+ # Dump dict and inspect content
+ res = client.ft().dict_dump("custom_dict")
+ assert ["item1", "item3"] == res
+
+ # Remove rest of the items before reload
+ client.ft().dict_del("custom_dict", *res)
+
+
+@pytest.mark.redismod
+def test_phonetic_matcher(client):
+ client.ft().create_index((TextField("name"),))
+ client.ft().add_document("doc1", name="Jon")
+ client.ft().add_document("doc2", name="John")
+
+ res = client.ft().search(Query("Jon"))
+ assert 1 == len(res.docs)
+ assert "Jon" == res.docs[0].name
+
+ # Drop and create index with phonetic matcher
+ client.flushdb()
+
+ client.ft().create_index((TextField("name", phonetic_matcher="dm:en"),))
+ client.ft().add_document("doc1", name="Jon")
+ client.ft().add_document("doc2", name="John")
+
+ res = client.ft().search(Query("Jon"))
+ assert 2 == len(res.docs)
+ assert ["John", "Jon"] == sorted([d.name for d in res.docs])
+
+
+@pytest.mark.redismod
+def test_scorer(client):
+ client.ft().create_index((TextField("description"),))
+
+ client.ft().add_document(
+ "doc1", description="The quick brown fox jumps over the lazy dog"
+ )
+ client.ft().add_document(
+ "doc2",
+ description="Quick alice was beginning to get very tired of sitting by her quick sister on the bank, and of having nothing to do.", # noqa
+ )
+
+ # default scorer is TFIDF
+ res = client.ft().search(Query("quick").with_scores())
+ assert 1.0 == res.docs[0].score
+ res = client.ft().search(Query("quick").scorer("TFIDF").with_scores())
+ assert 1.0 == res.docs[0].score
+ res = client.ft().search(
+ Query("quick").scorer("TFIDF.DOCNORM").with_scores())
+ assert 0.1111111111111111 == res.docs[0].score
+ res = client.ft().search(Query("quick").scorer("BM25").with_scores())
+ assert 0.17699114465425977 == res.docs[0].score
+ res = client.ft().search(Query("quick").scorer("DISMAX").with_scores())
+ assert 2.0 == res.docs[0].score
+ res = client.ft().search(Query("quick").scorer("DOCSCORE").with_scores())
+ assert 1.0 == res.docs[0].score
+ res = client.ft().search(Query("quick").scorer("HAMMING").with_scores())
+ assert 0.0 == res.docs[0].score
+
+
+@pytest.mark.redismod
+def test_get(client):
+ client.ft().create_index((TextField("f1"), TextField("f2")))
+
+ assert [None] == client.ft().get("doc1")
+ assert [None, None] == client.ft().get("doc2", "doc1")
+
+ client.ft().add_document(
+ "doc1", f1="some valid content dd1", f2="this is sample text ff1"
+ )
+ client.ft().add_document(
+ "doc2", f1="some valid content dd2", f2="this is sample text ff2"
+ )
+
+ assert [
+ ["f1", "some valid content dd2", "f2", "this is sample text ff2"]
+ ] == client.ft().get("doc2")
+ assert [
+ ["f1", "some valid content dd1", "f2", "this is sample text ff1"],
+ ["f1", "some valid content dd2", "f2", "this is sample text ff2"],
+ ] == client.ft().get("doc1", "doc2")
+
+
+@pytest.mark.redismod
+@skip_ifmodversion_lt("2.2.0", "search")
+def test_config(client):
+ assert client.ft().config_set("TIMEOUT", "100")
+ with pytest.raises(redis.ResponseError):
+ client.ft().config_set("TIMEOUT", "null")
+ res = client.ft().config_get("*")
+ assert "100" == res["TIMEOUT"]
+ res = client.ft().config_get("TIMEOUT")
+ assert "100" == res["TIMEOUT"]
+
+
+@pytest.mark.redismod
+def test_aggregations(client):
+ # Creating the index definition and schema
+ client.ft().create_index(
+ (
+ NumericField("random_num"),
+ TextField("title"),
+ TextField("body"),
+ TextField("parent"),
+ )
+ )
+
+ # Indexing a document
+ client.ft().add_document(
+ "search",
+ title="RediSearch",
+ body="Redisearch impements a search engine on top of redis",
+ parent="redis",
+ random_num=10,
+ )
+ client.ft().add_document(
+ "ai",
+ title="RedisAI",
+ body="RedisAI executes Deep Learning/Machine Learning models and managing their data.", # noqa
+ parent="redis",
+ random_num=3,
+ )
+ client.ft().add_document(
+ "json",
+ title="RedisJson",
+ body="RedisJSON implements ECMA-404 The JSON Data Interchange Standard as a native data type.", # noqa
+ parent="redis",
+ random_num=8,
+ )
+
+ req = aggregations.AggregateRequest("redis").group_by(
+ "@parent",
+ reducers.count(),
+ reducers.count_distinct("@title"),
+ reducers.count_distinctish("@title"),
+ reducers.sum("@random_num"),
+ reducers.min("@random_num"),
+ reducers.max("@random_num"),
+ reducers.avg("@random_num"),
+ reducers.stddev("random_num"),
+ reducers.quantile("@random_num", 0.5),
+ reducers.tolist("@title"),
+ reducers.first_value("@title"),
+ reducers.random_sample("@title", 2),
+ )
+
+ res = client.ft().aggregate(req)
+
+ res = res.rows[0]
+ assert len(res) == 26
+ assert "redis" == res[1]
+ assert "3" == res[3]
+ assert "3" == res[5]
+ assert "3" == res[7]
+ assert "21" == res[9]
+ assert "3" == res[11]
+ assert "10" == res[13]
+ assert "7" == res[15]
+ assert "3.60555127546" == res[17]
+ assert "10" == res[19]
+ assert ["RediSearch", "RedisAI", "RedisJson"] == res[21]
+ assert "RediSearch" == res[23]
+ assert 2 == len(res[25])
+
+
+@pytest.mark.redismod
+@skip_ifmodversion_lt("2.0.0", "search")
+def test_index_definition(client):
+ """
+ Create definition and test its args
+ """
+ with pytest.raises(RuntimeError):
+ IndexDefinition(prefix=["hset:", "henry"], index_type="json")
+
+ definition = IndexDefinition(
+ prefix=["hset:", "henry"],
+ filter="@f1==32",
+ language="English",
+ language_field="play",
+ score_field="chapter",
+ score=0.5,
+ payload_field="txt",
+ index_type=IndexType.JSON,
+ )
+
+ assert [
+ "ON",
+ "JSON",
+ "PREFIX",
+ 2,
+ "hset:",
+ "henry",
+ "FILTER",
+ "@f1==32",
+ "LANGUAGE_FIELD",
+ "play",
+ "LANGUAGE",
+ "English",
+ "SCORE_FIELD",
+ "chapter",
+ "SCORE",
+ 0.5,
+ "PAYLOAD_FIELD",
+ "txt",
+ ] == definition.args
+
+ createIndex(client.ft(), num_docs=500, definition=definition)
+
+
+@pytest.mark.redismod
+@skip_ifmodversion_lt("2.0.0", "search")
+def test_create_client_definition(client):
+ """
+ Create definition with no index type provided,
+ and use hset to test the client definition (the default is HASH).
+ """
+ definition = IndexDefinition(prefix=["hset:", "henry"])
+ createIndex(client.ft(), num_docs=500, definition=definition)
+
+ info = client.ft().info()
+ assert 494 == int(info["num_docs"])
+
+ client.ft().client.hset("hset:1", "f1", "v1")
+ info = client.ft().info()
+ assert 495 == int(info["num_docs"])
+
+
+@pytest.mark.redismod
+@skip_ifmodversion_lt("2.0.0", "search")
+def test_create_client_definition_hash(client):
+ """
+ Create definition with IndexType.HASH as index type (ON HASH),
+ and use hset to test the client definition.
+ """
+ definition = IndexDefinition(
+ prefix=["hset:", "henry"],
+ index_type=IndexType.HASH
+ )
+ createIndex(client.ft(), num_docs=500, definition=definition)
+
+ info = client.ft().info()
+ assert 494 == int(info["num_docs"])
+
+ client.ft().client.hset("hset:1", "f1", "v1")
+ info = client.ft().info()
+ assert 495 == int(info["num_docs"])
+
+
+@pytest.mark.redismod
+@skip_ifmodversion_lt("2.2.0", "search")
+def test_create_client_definition_json(client):
+ """
+ Create definition with IndexType.JSON as index type (ON JSON),
+ and use json client to test it.
+ """
+ definition = IndexDefinition(prefix=["king:"], index_type=IndexType.JSON)
+ client.ft().create_index((TextField("$.name"),), definition=definition)
+
+ client.json().set("king:1", Path.rootPath(), {"name": "henry"})
+ client.json().set("king:2", Path.rootPath(), {"name": "james"})
+
+ res = client.ft().search("henry")
+ assert res.docs[0].id == "king:1"
+ assert res.docs[0].payload is None
+ assert res.docs[0].json == '{"name":"henry"}'
+ assert res.total == 1
+
+
+@pytest.mark.redismod
+@skip_ifmodversion_lt("2.2.0", "search")
+def test_fields_as_name(client):
+ # create index
+ SCHEMA = (
+ TextField("$.name", sortable=True, as_name="name"),
+ NumericField("$.age", as_name="just_a_number"),
+ )
+ definition = IndexDefinition(index_type=IndexType.JSON)
+ client.ft().create_index(SCHEMA, definition=definition)
+
+ # insert json data
+ res = client.json().set(
+ "doc:1",
+ Path.rootPath(),
+ {"name": "Jon", "age": 25}
+ )
+ assert res
+
+ total = client.ft().search(
+ Query("Jon").return_fields("name", "just_a_number")).docs
+ assert 1 == len(total)
+ assert "doc:1" == total[0].id
+ assert "Jon" == total[0].name
+ assert "25" == total[0].just_a_number
+
+
+@pytest.mark.redismod
+@skip_ifmodversion_lt("2.2.0", "search")
+def test_search_return_fields(client):
+ res = client.json().set(
+ "doc:1",
+ Path.rootPath(),
+ {"t": "riceratops", "t2": "telmatosaurus", "n": 9072, "flt": 97.2},
+ )
+ assert res
+
+ # create index on
+ definition = IndexDefinition(index_type=IndexType.JSON)
+ SCHEMA = (
+ TextField("$.t"),
+ NumericField("$.flt"),
+ )
+ client.ft().create_index(SCHEMA, definition=definition)
+ waitForIndex(client, "idx")
+
+ total = client.ft().search(
+ Query("*").return_field("$.t", as_field="txt")).docs
+ assert 1 == len(total)
+ assert "doc:1" == total[0].id
+ assert "riceratops" == total[0].txt
+
+ total = client.ft().search(
+ Query("*").return_field("$.t2", as_field="txt")).docs
+ assert 1 == len(total)
+ assert "doc:1" == total[0].id
+ assert "telmatosaurus" == total[0].txt
+
+
+@pytest.mark.redismod
+def test_synupdate(client):
+ definition = IndexDefinition(index_type=IndexType.HASH)
+ client.ft().create_index(
+ (
+ TextField("title"),
+ TextField("body"),
+ ),
+ definition=definition,
+ )
+
+ client.ft().synupdate("id1", True, "boy", "child", "offspring")
+ client.ft().add_document(
+ "doc1",
+ title="he is a baby",
+ body="this is a test")
+
+ client.ft().synupdate("id1", True, "baby")
+ client.ft().add_document(
+ "doc2",
+ title="he is another baby",
+ body="another test"
+ )
+
+ res = client.ft().search(Query("child").expander("SYNONYM"))
+ assert res.docs[0].id == "doc2"
+ assert res.docs[0].title == "he is another baby"
+ assert res.docs[0].body == "another test"
+
+
+@pytest.mark.redismod
+def test_syndump(client):
+ definition = IndexDefinition(index_type=IndexType.HASH)
+ client.ft().create_index(
+ (
+ TextField("title"),
+ TextField("body"),
+ ),
+ definition=definition,
+ )
+
+ client.ft().synupdate("id1", False, "boy", "child", "offspring")
+ client.ft().synupdate("id2", False, "baby", "child")
+ client.ft().synupdate("id3", False, "tree", "wood")
+ res = client.ft().syndump()
+ assert res == {
+ "boy": ["id1"],
+ "tree": ["id3"],
+ "wood": ["id3"],
+ "child": ["id1", "id2"],
+ "baby": ["id2"],
+ "offspring": ["id1"],
+ }
diff --git a/tests/testdata/titles.csv b/tests/testdata/titles.csv
new file mode 100644
index 0000000..6428dd2
--- /dev/null
+++ b/tests/testdata/titles.csv
@@ -0,0 +1,4861 @@
+bhoj shala,1
+radhika balakrishnan,1
+ltm,1
+sterlite energy,1
+troll doll,11
+sonnontio,1
+nickelodeon netherlands kids choice awards,1
+jamaica national basketball team,5
+clan mackenzie,1
+secure attention key,3
+template talk indo pakistani war of 1971,1
+hassan firouzabadi,2
+carter alan,1
+alan levy,1
+tim severin,2
+faux pas derived from chinese pronunciation,1
+jruby,3
+tobias nielsén,1
+avro 571 buffalo,1
+treasury stock,17
+שלום,10
+oxygen 19,1
+ntru,4
+tennis racquet,1
+place of birth,4
+council of canadians,1
+urshu,1
+american hotel,1
+dow corning corporation,3
+language based learning disability,3
+meri aashiqui tum se hi,30
+specificity,9
+edward l hedden,1
+pelli chesukundam,2
+of love and shadows,4
+fort san felipe,2
+american express gold card dress of lizzy gardiner,4
+jovian,5
+kitashinagawa station,1
+radhi jaidi,1
+cordelia scaife may,2
+minor earth major sky,1
+bunty lawless stakes,1
+high capacity color barcode,3
+lyla lerrol,1
+crawford roberts,1
+collin balester,1
+ugo crousillat,1
+om prakash chautala,3
+izzy hoyland,1
+the poet,2
+daryl sabara,6
+aromatic acid,2
+reina sofia,1
+swierczek masovian voivodeship,1
+housing segregation in the united states,2
+karen maser,1
+scaptia beyonceae,2
+kitakyushu city,1
+htc desire 610,4
+dostoevsky,3
+portal victorian era,1
+bose–einstein correlations,3
+ralph hodgson,1
+racquet club,2
+walter camp man of the year,1
+australian movies,1
+k04he,1
+australia–india relations,2
+john william howard thompson,1
+pro cathedral,1
+paddyfield pipit,2
+book finance,1
+ford maverick,10
+slurve,4
+mnozil brass,2
+fiesta 9 1/8 inch square luncheon plate sunflower,1
+korsi,1
+draft 140th operations group,2
+camp,29
+series acceleration,1
+aljouf,1
+democratic party of new mexico,2
+united kingdom general election debates 2010,2
+madura strait,2
+back examination,1
+borgata,2
+il ritorno di tobia,3
+ovaphagous,1
+motörhead,9
+hellmaster,1
+richard keynes,1
+cryogenic treatment,3
+monte porzio,1
+transliteration of arabic,1
+anti catholic,2
+a very merry pooh year,2
+suffixes in hebrew,3
+barr body,16
+alaska constitution,1
+juan garrido,1
+yi lijun,1
+wawa inc,2
+endre kelemen,1
+l brands,18
+lr44,1
+coat of arms of the nagorno karabakh republic,1
+antonino fernandez,1
+salisbury roller girls,1
+zayat,2
+ian meadows,2
+semigalia,1
+khloe and lamar,2
+holding,1
+larchmont edgewater,1
+dynamic parcel distribution,6
+seaworld,30
+assistant secretary of war,1
+digital currency,14
+mazomanie wisconsin,1
+sujatha rangarajan,8
+street child,1
+anna sheehan,1
+violence jack,2
+santi solari,1
+template talk texas in the civil war,1
+colorss foundation,1
+faucaria,1
+alfred gardyne de chastelain,2
+tramp,1
+cannington ontario,2
+penguinone,1
+cardiac arrest,2
+summan grouper,1
+cyndis list,1
+cbs,2
+salminus brasiliensis,2
+kodiak bear,26
+cinemascore,9
+phragmidium,1
+city of vultures,1
+lawrence g romo,1
+chandni chowk to china,1
+scarp retreat,1
+rosses point,1
+carretera de cádiz,1
+chamunda,8
+battle of stalingrad,1
+who came first,2
+salome,5
+portuguese historical museum,3
+westfield sarasota square,1
+muehrckes nails,3
+kennebec north carolina,1
+american classical league,1
+how do you like them apples,1
+mark halperin,20
+circo,1
+turner classic movies,2
+australian rules football in sweden,1
+household silver,3
+frank baird,1
+escape from east berlin,2
+a village romeo and juliet,1
+wally nesbitt,6
+joseph renzulli,2
+spalding gray,1
+dangaria kandha,1
+pms asterisk,2
+openal,1
+romy haag,1
+mh message handling system,4
+pioneer 4,4
+hmcs stettler,1
+gangsta,10
+major third,4
+joan osbourn,1
+mount columbia,2
+active galactic nucleus,14
+robert clary,8
+eva pracht,1
+ion implantation,5
+rydell poepon,4
+baller blockin,2
+enfield chase railway station,1
+serge aurier,13
+florin vlaicu,1
+van diemens land,9
+krishnapur bagalkot,1
+oleksandr zinchenko,96
+collaborations,2
+hecla,2
+amber marshall,7
+inácio henrique de gouveia,1
+bronze age korea,1
+slc punk,5
+ryan jack,2
+clathrus ruber,6
+angel of death,4
+valentines park,1
+extra pyramidal,1
+kiami davael,1
+oleg i shuplyak,1
+nidum,2
+friendship of salem,2
+bèze,3
+arnold weinstock,1
+able,1
+s d ugamchand,1
+the omega glory,2
+ami james,3
+denmark at the 1968 summer olympics,1
+kill me again,1
+richmond town square,1
+guy domville,1
+jessica simpson,1
+kinship care,1
+brugge railway station,2
+unobtainium,16
+carl johan bernadotte,3
+acacia concinna,5
+epinomis,1
+interlachen country club,1
+compromise tariff,1
+fairchild jk,1
+dog trainer,1
+brian dabul,1
+cai yong,1
+jezebel,7
+augarten porcelain,1
+summerslam 1992,1
+ion andoni goikoetxea,2
+dominican church vienna,1
+iffhs worlds best club coach,2
+uruguayan presidential election 2009,2
+saving the queen,1
+un cadavre,1
+history of the jews in france,4
+wbyg,1
+charles de brosses,2
+human weapon,2
+haunted castle,3
+austin maestro,1
+search for extra terrestrial intelligence,1
+suwon,9
+cost per impression,1
+osney lock,1
+markus eriksson,1
+cultural depictions of tony blair,2
+erich kempka,3
+pornogrind,5
+chekhov,1
+marilinda garcia,2
+hard drive,1
+small arms,9
+exploration of north america,8
+international korfball federation,1
+photographic lens design,4
+k hari prasad,1
+lebanese forces,3
+greece at the 2004 summer olympics,1
+lets trim our hair in accordance with the socialist lifestyle,2
+battle of cassinga,5
+donald and the wheel,1
+vti transmission,1
+gille chlerig earl of mar,1
+heart of atlanta motel inc v united states,6
+oh yeah,3
+carol decker,5
+prajakta shukre,4
+profiling,17
+thukima,1
+the great waldo search,1
+nick vincent,2
+the decision of the appeals jury is final and can only be overruled by a decision of the executive committee 2e,1
+civilization board game,1
+erasmus+,1
+eden phillpotts,1
+unleash the beast,1
+varoujan hakhbandian,1
+fermats last theorem,1
+conan the indomitable,1
+vagrant records,1
+house of villehardouin,1
+zoneyesha ulatha,1
+ashur bel nisheshu,1
+ten wijngaerde,2
+lgi homes,1
+american nietzsche a history of an icon and his ideas,1
+european magpie,3
+pablo soto,1
+terminiello v chicago,1
+vladimir cosma,2
+battle of yunnan burma road,1
+ophirodexia,1
+thudar,1
+northern irish,2
+bohemond of tarente,1
+anita moorjani,5
+serra do gerês,1
+fort horsted,1
+metre gauge,2
+stage show,3
+common flexor sheath of hand,2
+conall corc,1
+array slicing,6
+schüfftan process,1
+anmol malik,3
+out cold,2
+antiknock,2
+moss force,1
+paul medhurst,1
+somonauk illinois,1
+george crum,11
+baby talk,6
+daniel mann,4
+vacuum flask,10
+prostitution in the republic of ireland,5
+butch jones,7
+feminism in ukraine,1
+st marys church kilmore county wexford,1
+sonny emory,1
+satsuma han,1
+elben,1
+the best of the rippingtons,3
+m3p,1
+boat sharing,1
+iisco,1
+hoftoren,1
+cannabis in the united kingdom,6
+template talk germany districts saxony anhalt,1
+jean baptiste dutrou bornier,1
+teylers museum,1
+simons problem,2
+gerardus huysmans,1
+pupillary distance,5
+jane lowe,1
+palais de justice brussels,1
+hillsdale free will baptist college,1
+raf wattisham,2
+parnataara,1
+jensen beach campus of the florida institute of technology,1
+scottish gypsy and traveller groups,3
+cliffs shaft mine museum,3
+roaring forties,4
+where in time is carmen sandiego?,2
+perfect field,1
+rob schamberger,1
+lcd soundsystem,10
+alan rathbone,26
+setup,1
+gliding over all,4
+dastur,1
+flensburger brauerei,3
+berkeley global campus at richmond bay,1
+kanakapura,1
+mineworkers union of namibia,1
+tokneneng,3
+mapuche textiles,3
+peranakan beaded slippers,1
+goodra,2
+kanab ut,1
+the gold act 1968,4
+grey langur,1
+procol harum,5
+chris alexander,1
+ft walton beach metropolitan area,3
+dimensionless quantity,16
+the science of mind,1
+alfons schone,1
+euparthenos nubilis,1
+batrachotoxin,5
+fabric live 22,1
+mchenry boatwright,1
+langney sports club,1
+akela jones,1
+lookout,2
+matsuo tsurayaba,2
+general jackson,3
+hair removal,14
+african party for the independence of cape verde,4
+replica trick,1
+bromfenac,2
+make someone happy,1
+sam pancake,1
+denys finch hatton,10
+latin rhythm albums,1
+main bronchus,1
+campidoglio,4
+cathaoirleach,1
+emress justina,1
+sulzbach hesse,1
+noncicatricial alopecia,1
+sylvan place,4
+stalag i c,1
+league of extraordinary gentlemen,1
+sergey korolyov,2
+serbian presidential election 1997,1
+barnes lake millers lake michigan,1
+christmas island health centre,1
+dayton ballet,2
+gilles fauconnier,1
+harald svergja,1
+joanna newsom discography,2
+astro xi yue hd,1
+code sharing,3
+dreamcast vmu,1
+armand emmanuel du plessis duc de richelieu,1
+ecole supérieure des arts du cirque,2
+gerry mulligan,12
+kaaka kaaka,1
+mexico at the 2012 summer olympics,4
+bar wizards,2
+christmas is almost here again,2
+sterling heights michigan,4
+gaultheria procumbens,3
+eben etzebeth,8
+viktorija Čmilytė,1
+los angeles county california,39
+family entertainment,2
+quantum well,9
+elton,1
+allan frewin jones,1
+daniela ruah,32
+gkd legend,1
+coffman–graham algorithm,1
+santa clara durango,1
+brian protheroe,3
+crawler transporter,10
+lakshman,3
+fes el bali,2
+mary a krupsak,1
+irish rugby football union,5
+neuropsychiatry,2
+josé pirela,1
+bonaire status referendum 2015,1
+it,2
+playhouse in the park,1
+alexander yakovlev,7
+old bear,1
+graph tool,2
+merseyside west,1
+romanian armies in the battle of stalingrad,1
+dark they were and golden eyed,1
+aidan obrien,8
+town and davis,1
+suum cuique,3
+german american day,2
+northampton county pennsylvania,3
+candidates of the south australian state election 2010,1
+venator marginatus,2
+k60an,1
+template talk campaignbox seven years war european,1
+maravi,1
+flaithbertach ua néill,1
+junction ohio,1
+dave walter,1
+london transport board,1
+tuyuka,1
+the moodys,3
+noel,3
+eugen richter,1
+cowanshannock township armstrong county pennsylvania,1
+pre columbian gold museum,1
+lac demosson,1
+lincosamides,9
+the vegas connection,1
+stephen e harris,1
+alkali feldspar,2
+brant hansen,1
+draft carnatic music stub,4
+the chemicals between us,1
+blood and bravery,1
+san diego flash,3
+covert channel,5
+ernest w adams,1
+hills brothers coffee,1
+cosmic background explorer,4
+international union of pure and applied physics,2
+vladimir kramnik,21
+hinterland,2
+tinker bell and the legend of the neverbeast,5
+ophisops jerdonii,1
+fine gold,1
+net explosive quantity,3
+miss colorado teen usa,3
+royal philharmonic orchestra discography,1
+elyazid maddour,1
+matthew kelly,2
+templating language,1
+japan campaign,2
+barack obama on mass surveillance,2
+thomas r donahue,1
+old right,4
+spencer kimball,1
+golden kela awards,1
+blinn college,3
+w k simms,1
+quinto romano,1
+richard mulrooney,1
+mr backup z64,1
+monetization of us in kind food aid,1
+alex chilton,2
+propaganda in the peoples republic of china,4
+jiří skalák,8
+m5 stuart tank,1
+template talk ap defensive players of the year,1
+crisis,2
+azuchi momoyama period,1
+care and maintenance,2
+a$ap mob,3
+near field communication,111
+hips hips hooray,1
+promotional cd,1
+andean hairy armadillo,1
+trigueros del valle,1
+elmwood illinois,1
+cantonment florida,2
+margo t oge,1
+national park service,36
+monongalia county ballpark,3
+bakemonogatari,6
+felicia michaels,1
+institute of oriental studies of the russian academy of sciences,2
+economy of eritrea,2
+vincenzo chiarenza,1
+microelectronics,4
+fresno state bulldogs mens basketball,1
+maotou,1
+blokely,1
+duplicati,3
+goud,2
+niki reiser,1
+edward leonard ellington,1
+jaswant singh of marwar,1
+biharsharif,1
+dynasty /trackback/,1
+machrihanish,4
+jay steinberg,1
+peter luger steak house,3
+palookaville,1
+ferrari grand prix results,2
+bankruptcy discharge,2
+mike mccue,2
+nuestra belleza méxico 2013,2
+alex neal bullen,1
+gus macdonald baron macdonald of tradeston,2
+florida circuit court,1
+haarp,2
+v pudur block,1
+grocer,1
+shmuel hanavi,1
+isaqueena falls,2
+jean moulin university,1
+final fantasy collection,1
+template talk american frontier,1
+chex quest,4
+muslim students association,2
+marco pique,1
+jinja safari,1
+the collection,9
+urban districts of germany,5
+rajiv chilaka,1
+zion,2
+vf 32,1
+united states commission on civil rights,2
+zazam,1
+barnettas,4
+rebecca blasband,1
+lincoln village,1
+film soundtracks,1
+angus t jones,77
+snuppy,3
+w/indexphp,30
+file talk american world war ii senior military officials 1945jpeg,1
+worship leader,1
+ein qiniya,1
+buxton maine,1
+matt dewitt,1
+béla bollobás,3
+earlysville union church,1
+bae/mcdonnell douglas harrier ii gr9,1
+californian condor,2
+progressive enhancement,15
+its not my time,4
+ecw on tnn,2
+ihop,36
+aeronautical chart,1
+clique width,1
+fuengirola,8
+archicebus achilles,2
+comparison of alcopops,1
+carla anderson hills,1
+roanoke county virginia,2
+jaílson alves dos santos,1
+rameses revenge,1
+kaycee stroh,5
+les experts,1
+niels skousen,1
+apollo hoax theories,1
+mercedes w204,2
+enhanced mitigation experience toolkit,15
+bert barnes,1
+serializability,6
+ten plagues of egypt,1
+joe l brown,1
+category talk high importance chicago bears articles,1
+stephen caffrey,3
+european border surveillance system,2
+achytonix,1
+m2 machine gun,1
+gurieli,1
+kunefe,1
+m33 helmet,3
+little carmine,1
+smush,3
+josé horacio gómez,1
+product recall,1
+egger,1
+wisconsin highway 55,1
+harbledown,1
+low copy repeats,1
+curt gentry,1
+united colors of benetton,1
+adiabatic shear band,2
+pea galaxy,1
+where are you now,1
+dils,1
+surprise s1,1
+senate oceans caucus,2
+windsor new hampshire,1
+a hawk and a hacksaw,1
+i love it loud,2
+milbcom,1
+old world vulture,7
+camara v municipal court of city and county of san francisco,1
+ski dubai,1
+st cyprians school,2
+aibo,1
+ticker symbol,2
+hendrik houthakker,1
+shivering,5
+jacob arminius,1
+mowming,1
+panjiva,2
+namco libble rabble,5
+rudolph bing,1
+sindhi cap,2
+logician,1
+ford xa falcon,2
+the sunny side up show,1
+helen adams,2
+kharchin,1
+brittany maynard,13
+kim kyu jong,1
+messier 103,3
+leon boiler,1
+the rapeman,1
+twa flight 3,4
+leading ladies,1
+delta octantis,2
+qatari nationality law,1
+lionel cripps,1
+josé daniel carreño,1
+crypsotidia longicosta,1
+polish falcons,1
+highlands north gauteng,1
+the florida channel,1
+oreste barale,1
+ghazi of iraq,2
+charles grandison finney,4
+ahmet ali,1
+abbeytown,1
+caribou,3
+big two,2
+alien,14
+aslantaş dam,3
+theme of the traitor and the hero,1
+vladimir solovyov,1
+laguna ojo de liebre,1
+clive barton,1
+ebrahim daoud nonoo,1
+richard goodwin keats,2
+back to the who tour 51,1
+entertainmentwise,1
+ja preston,1
+john astin,19
+strict function,1
+cam ranh international airport,2
+gary pearson,1
+sven väth,8
+toad,6
+johnny pace,1
+hunt stockwell,1
+rolando schiavi,1
+claudia grassl,1
+oxford nova scotia,1
+maryland sheep and wool festival,1
+conquest of bread,1
+erevan,1
+comparison of islamic and jewish dietary laws,11
+sheila burnford,1
+estevan payan,1
+ocean butterflies international,7
+the royal winnipeg rifles,1
+green goblin in other media,2
+video gaming in japan,8
+church of the guanche people,4
+gustav hartlaub,2
+ian mcgeechan,4
+hammer and sickle,17
+konkiep river,1
+ceri richards,1
+decentralized,2
+depth psychology,3
+centennial parkway,1
+yugoslav monitor vardar,1
+battle of bobbili,2
+magnus iii of sweden,1
+england c national football team,2
+thuraakunu,1
+bab el ehr,1
+koi,1
+cully wilson,1
+money laundering,1
+stirling western australia,1
+jennifer dinoia,1
+eureka street,1
+message / call my name,1
+make in maharashtra,4
+huckleberry creek patrol cabin,1
+almost famous,5
+truck nuts,4
+vocus communications,1
+gikwik,1
+battle of bataan,4
+confluence pennsylvania,2
+islander 23,1
+mv skorpios ii,1
+single wire earth return,1
+politics of odisha,1
+crédit du nord,3
+piper methysticum,2
+coble,2
+kathleen a mattea,1
+coachella valley music and arts festival,50
+tooniverse,1
+spofforth castle,1
+arabian knight,2
+two airlines policy,1
+hinduja group,17
+swagg alabama,1
+portuguese profanity,1
+loomis gang,2
+nina veselova,2
+aegyrcitherium,1
+bees in paradise,1
+béládys anomaly,3
+badalte rishtey,1
+first bank fc,1
+cystoseira,1
+red book of endangered languages,1
+rose,6
+terry mcgurrin,3
+jason hawke,1
+peter chernin,1
+tu 204,1
+the man who walked alone,1
+tool grade steel,1
+wrist spin,1
+one step forward two steps back,1
+theodor boveri,1
+heunginjimun,1
+fama–french three factor model,34
+billy whitehurst,1
+rip it up,4
+red lorry yellow lorry,4
+nao tōyama,8
+general macarthur,1
+rabi oscillation,2
+devín,1
+olympus e 420,1
+hydra entertainment,1
+chris cheney,3
+rio all suite hotel and casino,3
+the death gate cycle,2
+fatima,1
+kamomioya shrine,1
+five nights at freddys 3,14
+the broom of the system,3
+robert blincoe,1
+history of wells fargo,9
+pinocytosis,4
+leaf phoenix,1
+wxmw,2
+tommy henriksen,13
+geri halliwell discography,2
+blade runneri have seen things you would not believe,1
+madhwa brahmins,1
+i/o ventures,1
+edorisi master ekhosuehi,2
+junior orange bowl,1
+khit,2
+sue jones,1
+immortalized,35
+city building series,4
+quran translation,1
+united states consulate,1
+dose response relationship,1
+caitriona,1
+colocolo,21
+medea class destroyer,1
+vaastav,1
+etc1,1
+john altoon,2
+thylacine,113
+cycling at the 1924 summer olympics,1
+margaret nagle,1
+superpower,57
+gülşen,1
+anthems to the welkin at dusk,4
+yerevan united fc,1
+the family fang,14
+domain,4
+high speed rail in india,14
+trifolium pratense,7
+florida mountains,2
+national city corp,5
+length of us participation in major wars,2
+acacia acanthoclada,1
+offas dyke path,2
+enduro,7
+howard center,1
+littlebits,4
+plácido domingo jr,1
+hookdale illinois,1
+the love language,1
+cupids arrows,1
+dc talk,7
+maesopsis eminii,1
+here comes goodbye,1
+freddie foreman,5
+marvel comics publishers,1
+consolidated city–county,5
+countess marianne bernadotte of wisborg,1
+los angeles baptist high school,1
+maglalatik,1
+deo,2
+meilichiu,1
+wade coleman,1
+monster soul,2
+julion alvarez,2
+platinum 166,1
+shark week,12
+hossbach memorandum,4
+jack c massey,3
+ardore,1
+philosopher king,5
+dynamic random access memory,5
+bronze age in southeastern europe,1
+tamil films of 2012,1
+nathalie cely,1
+italian capital,1
+optic tract,3
+shakti kumar,1
+who killed bruce lee,1
+parlement of brittany,3
+san juan national historic site,2
+livewell,2
+template talk om,1
+al bell,2
+pzl w 3 sokół,8
+durrës rail station,3
+david stubbs,1
+pharmacon,3
+railfan,7
+comics by country,2
+cullen baker,1
+maximum subarray problem,19
+outlaws and angels,1
+paradise falls,2
+mathias pogba,28
+donella meadows,4
+john leconte,2
+swaziland national football team,7
+gabriele detti,2
+if ever youre in my arms again,1
+christian basso,1
+helen shapiro,7
+taisha abelar,1
+fluid dynamics,1
+ernest wilberforce,1
+kocaeli university,2
+british m class submarine,1
+modern woodmen of america,1
+las posadas,3
+federal budget of germany,2
+liberation front of chad,1
+sandomierz,5
+ap italian language and culture,1
+manuel gonzález,1
+georgian military road,2
+clear creek county colorado,1
+matt clark,2
+test tube,18
+ak 47,1
+diège,1
+london school of economics+,1
+michael york,14
+half eagle,6
+strike force,1
+type 054 frigate,2
+sino indian relations,7
+fern,3
+louvencourt,1
+ghb receptor,2
+chondrolaryngoplasty,2
+andrew lewer,1
+ross king,1
+colpix records,1
+october 28,1
+tatsunori hara,1
+rossana lópez león,1
+haskell texas,3
+tower subway,2
+waspstrumental,1
+template talk nba anniversary teams,1
+george leo leech,1
+still nothing moves you,1
+blood cancer,3
+buffy lynne williams,1
+dpgc u know what im throwin up,1
+daniel nadler,1
+khalifa sankaré,2
+homo genus,1
+garðar thór cortes,3
+veyyil,1
+matt dodge,1
+hipponix subrufus,1
+anostraca,1
+hartshill park,1
+purple acid phosphatases,1
+austromyrtus dulcis,1
+shamirpet lake,1
+favila of asturias,2
+acute gastroenteritis,1
+dalton cache pleasant camp border crossing,1
+urobilinogen,13
+ss kawartha park,1
+professional chess association,1
+species extinction,1
+gapa hele bi sata,1
+phyllis lyon and del martin,1
+uk–us extradition treaty of 2003,1
+a woman killed with kindness,1
+how bizarre,1
+norm augustine,1
+geil,1
+volleyball at the 2015 southeast asian games,2
+jim ottaviani,1
+chekmagushevskiy district,1
+information search process,2
+queer,63
+william pidgeon,1
+amelia adamo,1
+nato ouvrage "g",1
+tamsin beaumont,1
+economy of syria,13
+douglas dc 8 20,1
+tama and friends,4
+pringles,22
+kannada grammar,7
+lotoja,1
+peony,1
+bmmi,1
+eurovision song contest 1992,11
+cerro blanco metro station,1
+sherlock the riddle of the crown jewels,4
+dorsa cato,1
+nkg2d,8
+specific heat,6
+nokia 6310i,2
+tergum,2
+bahai temple,1
+dal segno,5
+leigh chapman,2
+tupolev tu 144,60
+flight of ideas,1
+rita montaner,1
+vivien a schmidt,1
+battle of the treasury islands,2
+three kinds of evil destination,1
+richlite,1
+medinilla,2
+timeline of aids,1
+colin renfrew baron renfrew of kaimsthorn,2
+hélène rollès,1
+pedro winter,1
+sabine free state,1
+brzeg,1
+palisades park,1
+gas gangrene,11
+dotyk,2
+daniela kix,1
+canna,16
+property list,9
+john hamburg,1
+dunk island,5
+albreda,1
+scammed yankees,1
+wireball,3
+junior 4,1
+absolutely anything,15
+linux operating system,1
+solsbury hill,15
+notopholia,1
+scottish heraldry,2
+template talk paper data storage media,1
+category talk religion in ancient sparta,1
+category talk cancer deaths in puerto rico,1
+mid michigan community college,2
+tvb anniversary awards,1
+frederick taylor gates,1
+omoiyari yosan,3
+journal of the physical society of japan,1
+kings in the corner,2
+nungua,1
+amerika,4
+pacific marine environmental laboratory,1
+the thought exchange,1
+italian bee,5
+roma in spain,1
+sirinart,1
+crandon wisconsin,1
+shubnikov–de haas effect,6
+portrait of maria portinari,4
+colin mcmanus,1
+universal personal telecommunications,1
+royal docks,4
+brecon and radnorshire,3
+eilema caledonica,1
+chalon sur saône,8
+toyota grand hiace,1
+sophorose,1
+semirefined 2bwax,1
+mechanics institute chess club,1
+the culture high,2
+dont wake me up,1
+transcaucasian mole vole,1
+harry zvi tabor,1
+vhs assault rifle,1
+playing possum,2
+omar minaya,2
+private university,1
+yuki togashi,3
+ski free,2
+say no more,1
+diving at the 1999 summer universiade,1
+armando sosa peña,1
+timur tekkal,1
+jura elektroapparate,1
+pornographic magazine,1
+tukur yusuf buratai,1
+keep on moving,1
+laboulbeniomycetes,1
+chiropractor solve problems,1
+mark s allen,3
+committees of the european parliament,4
+blondie,7
+veblungsnes,1
+bank vault,10
+smiling irish eyes,1
+robert kalina,2
+polarization ellipse,2
+huntingdon priory,1
+energy in the united kingdom,34
+hamble,1
+raja sikander zaman,1
+perigea hippia,1
+college of liberal arts and sciences,1
+bootblock,1
+nato reporting names,2
+the serpentwar saga,1
+reformed churches in the netherlands,1
+collaborative document review,4
+combat mission beyond overlord,3
+vlra,2
+pat st john,1
+oceanid,5
+itapetinga,1
+insane championship wrestling,9
+nathaniel gorham,1
+estadio metropolitano de fútbol de lara,2
+william of saint amour,2
+new york drama critics circle award,1
+alliant rq 6 outrider,2
+ilsan,1
+top model po russki,1
+woolens,1
+rutledge minnesota,1
+joigny coach crash,2
+zhou enlai the last perfect revolutionary,1
+the theoretical minimum,1
+arrow security,1
+john shelton wilder,2
+jasdf,2
+katie may,2
+american jewish military history project,1
+business professionals of america,1
+questioned document examination,5
+motorola a760,1
+american steel & wire,1
+louis armstrong at the crescendo vol 1,1
+edward vernon,3
+maria taipaleenmäki,1
+margical history tour,2
+jar jar,1
+australian oxford dictionary,2
+revenue service,2
+odoardo farnese hereditary prince of parma,1
+weekend in new england,1
+laurence harbor new jersey,2
+aramark tower,1
+stealers wheel,1
+cephalon,1
+dawnguard,1
+saintsbury,2
+saint fuscien,1
+ryoko kuninaka,1
+farm to market road 1535,1
+alan kennedy,2
+esteban casagolda,1
+shin angyo onshi,1
+william gowland,1
+eastern religions,6
+kenny lala,1
+alphonso davies,1
+tadamasa hayashi,1
+meet the parents,2
+calvinist church,1
+ristorante paradiso,1
+jose joaquim champalimaud,1
+olis,1
+mill hill school,2
+lockroy,1
+battle of princeton,10
+cent,8
+brough superior ss80,1
+ras al khaima club,3
+washington international university,3
+bradley kasal,2
+miguel Ángel varvello,1
+oxygen permeability,1
+femoral circumflex artery,1
+golden sun dark dawn,4
+pusarla sindhu,1
+toyota winglet,1
+wind profiler,1
+montefiore medical center,2
+template talk guitar hero series,3
+little leaf linden,1
+ramana,4
+islam in the czech republic,2
+manuel vitorino,1
+joseph radetzky von radetz,3
+francois damiens,1
+parasite fighter,1
+friday night at st andrews,3
+hurbazum,1
+haidhausen,1
+petabox,2
+salmonella enteritidis,2
+matthew r denver,1
+de la salle,1
+anti terrorism act 2015,6
+brugsen,1
+mountain times,1
+columbia basin project,1
+common wallaroo,2
+clepsis brunneograpta,1
+red hot + dance,1
+mao fumei,1
+dark shrew,1
+coach,8
+come saturday morning,1
+aanmai thavarael,1
+hellenia,1
+donate life america,2
+plot of beauty and the beast toronto musical,1
+births in 1243,3
+main page/wiki/portal technology,8
+cambridgeshire archives and local studies,1
+big pines california,1
+pegasus in popular culture,4
+baron glendonbrook,1
+your face sounds familiar,5
+boom tube,2
+richard gough,8
+the new beginning in niigata,3
+american academy of health physics,1
+plain,9
+tushino airfield,1
+king george v coronation medal,1
+geologic overpressure,1
+seille,1
+calorimeter,25
+french civil service,1
+david l paterson,1
+chinese gunboat chung shan,2
+rhizobium inoculants,1
+wizard,4
+baghestan,1
+paustian house,2
+ellen pompeo,55
+damien williams,1
+tomoe tamiyasu,1
+acute epithelial keratitis,1
+casey abrams,8
+mendozite,1
+kantian ethics,2
+mcclure syndicate,1
+tokyo metro,6
+cuisine of guinea bissau,1
+mossberg 500,18
+mollie gillen,1
+above and beyond party,1
+joey carbone,1
+faulkner state community college,1
+tetsuya ishikawa,1
+electric flag,3
+meet the feebles,2
+kplm,1
+when we were twenty one,1
+horus bird,2
+youth in revolt,8
+spongebob squarepants revenge of the flying dutchman,3
+ehow,5
+nikos xydakis,2
+ziprasidone,19
+ulsan airport,1
+flechtingen,1
+dave christian,3
+delaware national guard,1
+skaria thomas,1
+iraca,1
+kkhi,2
+swimming at the 2015 world aquatics championships – mens 1500 metre freestyle,2
+crossing lines,37
+john du cane,1
+i8,1
+bauer pottery,1
+affinity sutton,4
+lotus 119,1
+uss arleigh burke,1
+palmar interossei,2
+nofx discography,4
+bwia west indies airways,3
+gopala ii,1
+north fork correctional facility,1
+szeged 2011,1
+milligram per cent,2
+halas and batchelor,1
+what the day owes the night,1
+sighișoara medieval festival,5
+scarning railway station,1
+cambridge hospital,1
+amnesia labyrinth,2
+cokie roberts,7
+savings identity,3
+pravia,1
+mcgrath,4
+pakistan boy scouts association,1
+dan carpenter,2
+marikina–infanta highway,2
+genetic analysis,2
+template talk ohio state university,1
+thomas chamberlain,4
+moe book,1
+coyote waits,1
+black protestant,1
+neetu singh,19
+mahmoud sarsak,1
+casa loma,28
+bedivere,8
+boundary park,2
+danger danger,14
+jennifer coolidge,49
+pop ya collar,1
+collaboration with the axis powers during world war ii,10
+greenskeepers,1
+the dukes children,1
+alaska off road warriors,1
+twenty five satang coin,1
+template talk private equity investors,2
+american red cross,24
+jason shepherd,1
+georgetown college,2
+ocean countess,1
+ammonium magnesium phosphate,1
+community supported agriculture,5
+philosophy of suicide,4
+yard ramp,2
+captain germany,1
+bob klapisch,1
+i will never let you down,2
+february 11,6
+ron dennis,13
+rancid,16
+the mall blackburn,1
+south high school,6
+charles allen culberson,1
+organizational behavior,66
+automatic route selection,1
+uss the sullivans,9
+yo no creo en los hombres,1
+janet,1
+serena armstrong jones viscountess linley,3
+louisiana–lafayette ragin cajuns mens basketball,1
+flower films,1
+michelle ellsworth,1
+norbertine rite,2
+spanish mump,1
+shah jahan,67
+fraser coast region,1
+matt cornwell,1
+nra,1
+crested butte mountain resort,1
+college football playoff national championship,2
+craig heaney,4
+devil weed,1
+satsuki sho,1
+jordaan brown,1
+little annie,4
+thiha htet aung,1
+the disreputable history of frankie landau banks,1
+mickey lewis,1
+eldar nizamutdinov,1
+m1825 forage cap,1
+antonina makarova,1
+mopani district municipality,2
+al jahra sc,1
+chaim topol,4
+tum saath ho jab apne,1
+piff the magic dragon,7
+imagining argentina,1
+ni 62,1
+phys rev lett,1
+the peoples political party,1
+casoto,1
+popular movement of the revolution,4
+huntingtown maryland,1
+la bohème,33
+khirbat al jawfa,1
+lycksele zoo,1
+deveti krug,2
+cuba at the 2000 summer olympics,2
+rose wilson,7
+sammy lee,2
+dave sheridan,10
+universal records,2
+antiquities trade,3
+shoveller,1
+tapered integration,1
+parker pen company,4
+mushahid hussain syed,1
+nynehead,1
+counter reformation,2
+nhl on nbc,11
+ronny rosenthal,2
+arsenie todiraş,3
+lobster random,1
+halliburton,37
+gordon county georgia,1
+belle isle florida,3
+molly stanton,3
+green crombec,1
+geodesist,2
+abd al rahman al sufi,4
+demography of japan,26
+live xxx tv,5
+naihanchi,1
+cofinite,1
+msnbot,5
+clausard,1
+mimidae,1
+wind direction,15
+irrational winding of a torus,1
+tursiops truncatus,1
+trustee,1
+lumacaftor/ivacaftor,2
+balancing lake,2
+shoe trees,1
+cycling at the 1928 summer olympics – mens team pursuit,1
+calponia harrisonfordi,1
+hindu rate of growth,1
+dee gordon,7
+passion white flag,2
+frog skin,1
+rudolf eucken,2
+bayantal govisümber,1
+christopher a iannella,1
+robert myers,1
+james simons,1
+meng xuenong,1
+abayomi olonisakin,1
+milton wynants,1
+cincinnatus powell,1
+atomic bomb band,1
+hopfield network,12
+jet pocket top must,1
+the state of the world,1
+welf i duke of bavaria,2
+american civil liberties union v national security agency,3
+elizabeth fedde,1
+librarything,2
+kim fletcher,1
+tracy island,2
+praise song for the day,1
+superstar,7
+ewen spencer,1
+back striped weasel,1
+cs concordia chiajna,1
+bruce curry,1
+malificent,1
+dr b r ambedkar university,2
+river plate,1
+desha county arkansas,1
+harare declaration,2
+patrick dehornoy,1
+paul alan cox,2
+auckland mounted rifles regiment,1
+mikoyan gurevich dis,3
+corn exchange manchester,2
+sharpshooter,1
+the new york times manga best sellers of 2013,1
+max perutz,2
+andrei makolov,1
+inazuma eleven saikyō gundan Ōga shūrai,2
+tatra 816,1
+ashwin sanghi,8
+pipestone township michigan,1
+craig shoemaker,1
+david bateson,1
+lew lehr,1
+crewe to manchester line,2
+samurai champloo,36
+tali ploskov,2
+janet sobel,3
+kabe station,1
+rippon,1
+alexander iii equestrian,1
+louban,2
+the twelfth night,1
+delaware state forest,1
+the amazing race china 3,1
+brillouins theorem,1
+extreme north,3
+super frelon,1
+george watsons,1
+mungo park,1
+workin together,3
+boy,12
+brownsville toros,1
+kim lim,1
+futsal,63
+motoring taxation in the united kingdom,1
+accelerator physics codes,1
+arytenoid cartilage,3
+the price of beauty,3
+life on the murder scene,2
+hydrophysa psyllalis,1
+jürgen brandt,2
+economic history association,2
+the sandwich girl,1
+heber macmahon,1
+volume 1 sound magic,2
+san francisco–oakland–hayward ca metropolitan statistical area,9
+harriet green,7
+tarnawa kolonia,1
+eur1 movement certificate,20
+anna nolan,2
+gulf of gökova,1
+havertown,2
+orlando scandrick,4
+doug owston correctional centre,1
+asterionella,4
+espostoa,1
+ranked voting system,10
+commercial law,39
+kirk,1
+mongolian cuisine,8
+turfanosuchus,1
+arthur anderson,4
+sven olof lindholm,1
+batherton,1
+dimetrodon,1
+pianos become the teeth,1
+united kingdom in the eurovision song contest 1976,1
+medieval,11
+it bites,1
+ion television,8
+seaboard system railroad,3
+sayan mountains,3
+musaffah,1
+charles de foucauld,3
+urgh a music war,1
+translit,1
+american revolutionary war/article from the 1911 encyclopedia part 1,1
+uss mauna kea,1
+powder burn,1
+bald faced hornet,9
+producer of the year,1
+the most wanted man,1
+clear history,8
+mikael lilius,1
+class invariant,4
+forever michael,3
+goofing off,3
+tower viewer,3
+claudiu marin,1
+nicolas cage,1
+waol,2
+s10 nbc respirator,2
+education outreach,1
+gyeongsan,2
+template talk saints2008draftpicks,1
+botaurus,1
+francis harper,1
+mauritanian general election 1971,1
+kirsty roper,2
+non steroidal anti inflammatory drug,17
+nearchus of elea,2
+resistance to antiviral drugs,1
+raghavendra rajkumar,5
+template talk cc sa/sandbox,1
+washington gubernatorial election 2012,2
+paul lovens,1
+express freighters australia,2
+bunny bleu,2
+osaka prefecture,2
+federal reserve bank of boston,4
+hacı ahmet,1
+underground chapter 1,10
+filippo simeoni,2
+the wonderful wizard of oz,3
+sailing away,1
+avelino gomez memorial award,1
+badger,65
+hongkou football stadium,3
+benjamin f cheatham,2
+fair isaac,2
+kwab,1
+al hank aaron award,3
+gender in dutch grammar,1
+idiom neutral,2
+da lata,1
+tuu languages,1
+derivations are used,1
+clete patterson,1
+danish folklore,4
+android app //orgwikipedia/http/enmwikipediaorg/wiki/westfield academy,1
+toto,8
+ea,1
+victory bond tour,1
+credai,2
+hérin,1
+st james louisiana,1
+necrolestes,2
+cable knit,1
+saunderstown,1
+us route 52 in ohio,1
+sailors rest tennessee,1
+adlai stevenson i,6
+miscibility,13
+help footnotes,13
+murrell belanger,1
+new holland pennsylvania,5
+haldanodon,1
+feminine psychology,2
+riot city wrestling,1
+mobile content management system,2
+zinio,1
+central differencing scheme,2
+enoch,2
+usp florence admax,1
+maester aemon,7
+norman "lechero" st john,1
+ice racing,1
+tiger cub economies,6
+klaipėda region,12
+wu qian,8
+malayalam films of 1987,1
+estadio nuevo la victoria,1
+nanotoxicology,2
+hot revolver,1
+nives ivankovic,1
+glen edward rogers,5
+epicene,3
+eochaid ailtlethan,1
+judiciary of finland,1
+en jersey,1
+statc,1
+atta kim,1
+mizi research,2
+acs applied materials & interfaces,1
+thank god youre here,9
+loneliness,8
+h e b plus,2
+corella bohol,1
+money in the bank,59
+golden circle air t bird,1
+flash forward,1
+category talk philippine television series by network,1
+dfmda,1
+the road to wellville,8
+ernst tüscher,1
+commission,14
+abdul rahman bin faisal,6
+oversea chinese banking corporation,7
+ray malavasi,1
+al qadisiyah fc,4
+anisfield wolf book award,1
+jacques van rees,1
+jakki tha motamouth,1
+scoop,1
+piti,2
+carlos reyes,1
+v o chidambaram pillai,6
+diamonds sparkle,1
+the great transformation,5
+cardston alberta temple,1
+la vendetta,1
+miyota nagano,1
+national shrine of st elizabeth ann seton,2
+chaotic,1
+breastfeeding and hiv,1
+friedemann schulz von thun,1
+mukhammas,2
+fishbowl worldwide media,1
+mohamed amin,3
+john densmore,10
+suryadevara nayaks,1
+metal gear solid peace walker,12
+ché café,2
+old growth,1
+lake view cemetery,1
+konigsberg class cruiser,1
+courts of law,1
+nova scotia peninsula,3
+jairam ramesh,4
+portal kerala/introduction,1
+edinburgh 50 000 – the final push,1
+ludachristmas,3
+motion blur,1
+deliberative process privilege,2
+bubblegram,1
+simon breach grenade,2
+tess henley,1
+gojinjo daiko,1
+common support aircraft,2
+zelda rubinstein,9
+yolanda kakabadse,1
+american studio woodturning movement,1
+richard carpenter,67
+vehicle door,3
+transmission system operator,9
+christa campbell,9
+marolles en brie,1
+korsholma castle,1
+murder of annie le,3
+kims,1
+zionist union,8
+portal current events/june 2004,2
+marination,8
+cap haïtien international airport,2
+fujima kansai,1
+vampire weekend discography,3
+moncton coliseum,2
+wing chair,1
+el laco,2
+castle fraser,1
+template talk greek political parties,1
+society finch,1
+chief executive officer,4
+battle of bloody run,3
+coat of arms of tunisia,2
+nishi kawaguchi station,1
+colonoscopy,30
+vic tayback,5
+lonnie mack discography,3
+yusuf salman yusuf,2
+marco simone,4
+saint just,1
+elizabeth taylor filmography,6
+haglöfs,2
+yunis al astal,1
+daymond john,36
+bedd y cawr hillfort,1
+durjoy datta,1
+wealtheow,1
+aaron mceneff,1
+culture in berlin,1
+temple of saturn,6
+nermin zolotić,1
+the darwin awards,1
+patricio pérez,1
+chris levine,1
+misanthropic,1
+dragster,2
+eldar,19
+chrzanowo gmina szelków,1
+zimmerberg base tunnel,6
+jakob schaffner,1
+california gubernatorial recall election 2003,1
+tommy moe,1
+bikrami calendar,1
+mama said,11
+hellenic armed forces,8
+candy box,3
+monstervision,3
+kachin independent army,1
+pro choice,1
+tshiluba language,1
+trucial states,9
+collana,1
+best music video short form,1
+pokémon +giratina+and+the+sky+warrior,1
+etteldorf,1
+academic grading in chile,2
+land and liberty,3
+australian bureau of meteorology,1
+cheoin gu,1
+william henry green,1
+ewsd,2
+gate of hell,1
+sioux falls regional airport,3
+nevelj zsenit,1
+bevo lebourveau,1
+ranjana ami ar asbona,1
+shaun fleming,1
+jean antoine siméon fort,1
+sports book,1
+vedran smailović,3
+simple harmonic motion,29
+wikipedia talk wikiproject film/archive 16,1
+princess jasmine,13
+great bustard,5
+allred unit,1
+cheng san,1
+mini paceman,1
+flavoprotein,2
+storage wars canada,3
+university rowing,2
+category talk wikiproject saskatchewan communities,1
+the washington sun,1
+rotary dial,6
+hailar district,1
+assistant secretary of the air force,2
+the décoration for the yellow house,5
+chris mclennan,1
+the cincinnati kid,4
+education in the republic of ireland,15
+steve brodie,2
+country club of detroit,1
+wazner,1
+portal spain,4
+senna,3
+william j bernd house,1
+balaji baji rao,8
+worth dying for,1
+cool ruler,1
+turn your lights down low,2
+mavroudis bougaidis,1
+national registry emergency medical technician,1
+james young,8
+eyewire,1
+dark matters twisted but true/,1
+josé pascual monzo,1
+german election 1928,2
+linton vassell,1
+convention on the participation of foreigners in public life at local level,1
+thorium fuel cycle,5
+honeybaby honeybaby,1
+golestan palace,3
+lombok international airport,11
+mainichi daily news,1
+k&p,1
+liberal network for latin america,1
+cádiz memorial,1
+grupo corripio,1
+elie and earlsferry,1
+isidore geoffroy saint hilaire,1
+al salmiya sc,2
+piano sonata hob xvi/33,1
+e f bleiler,1
+national register of historic places listings in york county virginia,3
+gupta empire,2
+german immigration to the united states,1
+through gates of splendor,2
+iap,1
+love takes wing,1
+tours de merle,1
+aleksey zelensky,1
+paul almond,2
+boston cambridge quincy ma nh metropolitan statistical area,1
+komiks presents dragonna,1
+princess victoire of france,1
+alan pownall,3
+tilak nagar,2
+lg life sciences co ltd,8
+before their eyes,1
+labor right,5
+michiko to hatchin,1
+susan p graber,1
+xii,1
+hanswulf,1
+symbol rate,17
+myo18b,2
+rowing at the 2010 asian games – mens coxed eight,1
+caspar weinberger jr,2
+bettle juice,1
+battle of the morannon,7
+darlington county south carolina,1
+mayfield pennsylvania,1
+ruwerrupt de mad,1
+luthfi assyaukanie,1
+fiat panda,30
+wickiup reservoir,1
+tanabe–sugano diagram,6
+alexander sacher masoch prize,1
+intracellular transport,1
+church of the val de grâce,1
+jebel ad dair,1
+rosalind e krauss,6
+cross origin resource sharing,97
+readiness to sacrifice,1
+creel terrazas family,1
+phase portrait,9
+subepithelial connective tissue graft,1
+lake malawi,18
+phillips & drew,1
+ernst vom rath,2
+infinitus,1
+geneva convention for the amelioration of the condition of the wounded and sick in armies in the field,2
+world heritage,1
+dole whip,8
+leveling effect,1
+bioship,3
+vanilloids,2
+superionic conductor,1
+basil bernstein,7
+armin b cremers,2
+szlichtyngowa,1
+beixinqiao station,1
+united states presidential election in utah 1980,1
+watson v united states,3
+willie mcgill,1
+melle belgium,1
+al majmaah,1
+mesolimbic dopamine pathway,1
+six flags new england,5
+acp,2
+geostrategy,2
+original folk blues,1
+wentworth military academy,1
+bromodichloromethane,3
+doublet,4
+tawfiq al rabiah,1
+sergej jakirović,1
+mako surgical corp,3
+empire of lies,1
+old southwest,1
+bay of arguin,1
+bringing up buddy,1
+mustapha hadji,7
+raymond kopa,7
+evil horde,1
+kettering england,1
+extravaganza,1
+christian labour party,2
+joice mujuru,6
+v,15
+le père,4
+my fathers dragon,2
+cumulus cloud,32
+fantasy on themes from mozarts figaro and don giovanni,1
+postpone indefinitely,1
+extreme point,1
+iraq–israel relations,1
+henry le scrope 3rd baron scrope of masham,1
+rating beer,1
+claude alvin villee jr,2
+clackamas town center,2
+roope latvala,4
+richard bethell 1st baron westbury,1
+ryan gosling,1
+yelina salas,1
+amicus,1
+cecilia bowes lyon countess of strathmore and kinghorne,6
+programming style,9
+now and then,9
+somethingawful,1
+nuka hiva campaign,1
+bostongurka,2
+jorge luis ochoa vázquez,1
+philip burton,1
+rainbow fish,7
+road kill,5
+christiane frenette,2
+as if,1
+paul ricard,1
+roberto dañino,1
+shoyu,1
+jakarta,96
+dean keith simonton,1
+mastocytosis,19
+hiroko yakushimaru,3
+problem of other minds,2
+jaunutis,1
+tfp deficiency,1
+access atlantech edutainment,1
+kristian thulesen dahl,1
+william wei,1
+andy san dimas,10
+kempten/allgäu,1
+augustus caesar,9
+conrad janis,1
+tugaya lanao del sur,1
+second generation antipsychotics,1
+anema e core,2
+sucking the 70s,1
+the czars,2
+vakulabharanam,1
+f double sharp,3
+prymnesin,1
+dick bavetta,2
+billy jones,3
+columbine,4
+file talk joseph bidenjpg,1
+mandelbrot set,79
+constant elasticity of variance model,2
+morris method,1
+al shamal stadium,5
+hes alright,1
+madurai massacre,1
+philip kwon,2
+christadelphians,7
+this man is dangerous,2
+kiowa creek community church,1
+pier paolo vergerio,1
+order of the most holy annunciation,2
+john plender,1
+vallée de joux,2
+graysby,1
+ludwig minkus,3
+potato aphid,1
+bánh bột chiên,1
+wilhelmstraße,1
+fee waybill,1
+designed to sell,1
+ironfall invasion,2
+lieutenant governor of the isle of man,1
+third reading,2
+eleanor roosevelt high school,1
+su zhe,1
+heat conductivity,1
+si satchanalai national park,1
+etale space,1
+faq,24
+low carbohydrate diet,1
+differentiation of integrals,1
+karl fogel,2
+tom chapman,3
+james gamble rogers,2
+jeff rector,1
+burkut,9
+joe robinson,1
+turtle flambeau flowage,1
+moves like jagger,3
+turbaco,1
+oghuz turk,2
+latent human error,5
+square number,17
+rugby football league championship third division,2
+altoona pennsylvania,23
+circus tent,1
+satirical novel,1
+claoxylon,1
+barbaros class frigate,4
+oyer and terminer,2
+telephone numbers in the bahamas,1
+thomas c krajeski,2
+mv glenachulish,1
+sports broadcasting contracts in australia,3
+car audio,1
+ted lewis,2
+eric bogosian/robotstxt,2
+furman university japanese garden,1
+jed clampett,2
+flintstone,2
+c of tranquility,2
+rutali,2
+berkhamsted place,1
+wissam ben yedder,13
+nt5e,1
+erol onaran,1
+allium amplectens,1
+the three musketeers,2
+north eastern alberta junior b hockey league,1
+doggie daddy,1
+lauma,1
+the love racket,1
+eta hoffman,1
+ryans four,3
+omerta – city of gangsters,1
+humberview secondary school,2
+parels,1
+the descent,1
+evgenia linetskaya,1
+manhunt international 1994,1
+american society of animal science,1
+american samoa national rugby union team,1
+faster faster,1
+all creatures great and small,1
+mama said knock you out,9
+rozhdestveno memorial estate,2
+wizard of odd,1
+lugalbanda,4
+beardsley minnesota,1
+the rogue prince,10
+uss escambia,1
+stormy weather,3
+couleurs sur paris,1
+madrigal,4
+colin tibbett,1
+lemelson–mit prize,2
+phonetical singing,1
+glucophage,3
+suetonius,10
+ungra,1
+black and white minstrel,1
+woolwich west by election 1975,1
+trolleybuses in wellington,2
+jason macdonald,3
+ussr state prize,2
+robert m anderson,1
+kichijōji,1
+apache kid wilderness,1
+sneaky pete,8
+edward knight,1
+fabiano santacroce,1
+hemendra kumar ray,1
+sweat therapy,1
+stewart onan,2
+israel–turkey relations,1
+natalie krill,5
+clinoporus biporosus,1
+kosmos 2470,2
+vladislav sendecki,1
+healthcare in madagascar,1
+template talk 2010 european ryder cup team,1
+richard lyons,1
+transfer of undertakings regs 2006,3
+image processor,3
+alvin wyckoff,1
+kōbō abe,1
+kettle valley rail trail,1
+my baby just cares for me,3
+u28,1
+western australia police,10
+scincidae,1
+partitionism,1
+glenmorangie distillery tour,1
+river cave,1
+szilárd tóth,1
+i dont want nobody to give me nothing,1
+city,67
+annabel dover,2
+placebo discography,8
+showbiz,8
+solio ranch,1
+loan,191
+morgan james,10
+international federation of film critics,3
+the frankenstones,2
+pastor bonus,1
+billy purvis,1
+the gunfighters,1
+sandefjord,2
+ohio wine,2
+for the love of a man,1
+drifters,10
+ilhéus,1
+bikini frankenstein,1
+subterranean homesick alien,1
+chemical nomenclature,17
+great wicomico river,1
+ingrid caven,1
+japanese destroyer takanami,1
+nosler partition,1
+wagaman northern territory,1
+slovak presidential election 2019,1
+fuggerei,12
+al hibah,1
+irish war of independence,2
+joan smallwood,1
+anthony j celebrezze jr,1
+mercedes benz m130 engine,2
+phineas and ferb,2
+belgium womens national football team,3
+reynevan,1
+joe,1
+alan wilson,1
+epha3,1
+belarus national handball team,1
+phaedra,14
+move,2
+amateur rocketry,3
+epizootic hemorrhagic disease,5
+prague derby,4
+basilica of st thérèse lisieux,1
+pompeianus,1
+solved game,3
+tramacet,19
+essar energy,3
+lumbar stenosis,1
+part,24
+hải vân tunnel,1
+vsm group,3
+walter hooper,2
+consumer needs,1
+bell helicopter,18
+launde abbey,2
+ramune,10
+declarations of war during world war ii,1
+saint laurent de la salanque,1
+balkenbrij,1
+balgheim,1
+out of the box,13
+cappella,1
+national pharmaceutical pricing authority,4
+friend and foe,1
+new democracy,1
+eastern phoebe,2
+isipum of geumgwan gaya,1
+tel quel,1
+traveler,12
+superbeast,1
+oddsac,1
+zamora spain,1
+declaration of state sovereignty of the russian soviet federative socialist republic,1
+chumash painted cave state historic park california,3
+zentiva,1
+british rail class 88,5
+west indies cricket board,3
+pauli jørgensen,1
+punisher kills the marvel universe,7
+william de percy,1
+vehicle production group,4
+uc irvine anteaters mens volleyball,2
+dong sik yoon,1
+hyæna,2
+canadian industries limited,1
+mr ii,1
+jim muhwezi,1
+citizen jane,2
+night and day concert,1
+double precision floating point format,2
+herbal liqueurs,1
+the fixed period,5
+pip/taz,1
+lesser caucasus,2
+uragasmanhandiya,2
+alternative words for british,2
+khuzaima qutbuddin,1
+helmut balderis,2
+wesley r edens,1
+scott sassa,4
+mutant mudds,3
+east krotz springs louisiana,1
+leonard frey,3
+counting sort,15
+leandro gonzález pírez,2
+shula marks,1
+sierville,1
+california commission on teacher credentialing,1
+raymond loewy,10
+beevor foundry,1
+dog snapper,2
+hitman contracts,5
+eduard herzog,1
+wittard nemesis of ragnarok,1
+cape may light,1
+al saunders,3
+distant earth,2
+beam of light,2
+arent we all?,1
+veridicality,1
+private enterprise,3
+rambhadracharya,3
+dps,5
+beckdorf,1
+rúaidhrí de valera,1
+vivian bang,3
+sugar pine,1
+vn parameswaran pillai,1
+henry ross perot sr,1
+the arcadian,1
+the record,6
+g turner howard iii,1
+oleksandr usyk,12
+mumbai suburban district,5
+vicente dutra,1
+paean,1
+scottish piping society of london,1
+ingot,11
+alex obrien,6
+autonomous counties of china,1
+kaleorid,1
+remix & repent,3
+gender performativity,7
+godheadsilo,1
+tonsilloliths,1
+la dawri,1
+kiran more,3
+billboard music award for woman of the year,1
+tahitian ukulele,1
+buick lacrosse,14
+draft helen milner jury sent home for the night,2
+history of japanese cuisine,6
+time tunnel,1
+albert odyssey 2,1
+oysters rockefeller,4
+jim mahon,1
+evolutionary invasion analysis,1
+sunk cost fallacy,3
+universidad de manila,1
+morgan crucible,1
+southern miss golden eagles football,2
+horatio alger,13
+biological psychopathology,1
+hollywood,115
+product manager,21
+thomas burgh 3rd baron burgh,1
+stan hack,1
+peloponesian war,1
+republic of china presidential election 2004,2
+sanitarium,4
+growthgate,1
+samuel e anderson,1
+bobo faulkner,1
+kaffebrenneriet,1
+monponsett pond seaplane base,1
+powers of horror,3
+viburnum burkwoodii,1
+new suez canal,5
+gerardo ortíz,2
+japhia life,1
+paul pastur,1
+fuller craft museum,1
+nomal valley,1
+inaugural address,1
+saint Étienne du vigan,1
+lip ribbon microphone,2
+mary cheney,2
+piebald,6
+kadambas,1
+transportation in omaha,7
+before the league,1
+feltham and heston by election 2011,1
+aboriginal music of canada,3
+dnssec,6
+sshtunnels,1
+robin benway,1
+swimming at the 1968 summer olympics – mens 4 x 200 metre freestyle relay,1
+commission internationale permanente pour lepreuve des armes à feu portatives,3
+death rock,1
+hugo junkers,6
+gmt,3
+keanu reeves,2
+beverly kansas,1
+charlotte blair parker,1
+kids,5
+weight bench,1
+kiasmos,8
+basque country autonomous basketball team,1
+gideon toury,2
+gugak/,1
+texass 32nd congressional district,2
+have you ever been lonely,1
+take the weather with you,1
+chukchi,1
+the magicians wife,1
+juan manuel bordeu,1
+port gaverne,1
+music for films iii,1
+northern edo masquerades,1
+hang gliding,15
+marine corps logistics base barstow,2
+century iii mall,1
+peter tarlow,1
+thermal hall effect,1
+david ogden stiers,18
+webmonkey,1
+five cereals,2
+osceola washington,1
+clover virginia,2
+sphinginae,2
+stuart brace,1
+al di meola discography,7
+sunflowers,1
+hasty generalization,4
+polish athletic association,1
+the purge 3,2
+bitetti combat mma 4,1
+hiroko nagata,2
+mona seilitz,1
+mixed member proportional representation,7
+rancho temecula,2
+sinai,1
+norrmalmstorg robbery,5
+silesian walls,1
+floyd stahl,1
+gary becker,1
+knowledge engineering,5
+port of mobile,1
+luckiest girl alive,2
+ilya rabinovich,1
+bridge,3
+el general,3
+cornerstone schools,1
+gozmo,1
+charles courtney curran,1
+broker,32
+us senate committee on banking housing and urban affairs,2
+retroversion of the sovereignty to the people,1
+giorgi baramidze,1
+lars grael,1
+abdul qadir,3
+pgrep,2
+category talk seasons in danish womens football,1
+malus sieversii,1
+god squad,4
+category of acts,1
+melkote,1
+linda langston,1
+sherry romanado,1
+montana sky,8
+history of burkina faso,1
+iso 639 kxu,1
+los angeles fire department museum and memorial,1
+recognize,1
+der bewegte mann,6
+davy pröpper,1
+outline of vehicles,2
+gesta francorum,1
+sidney w pink,1
+ronald pierce,1
+martin munkácsi,1
+nord noreg,1
+accounting rate of return,7
+urwerk,1
+albert gallo,1
+antennaria dioica,3
+transport in sudan,2
+fladry,1
+cumayeri,1
+bennington college,11
+pêro de alenquer,2
+sixth man,1
+william i of aquitaine,1
+radisson diamond,1
+belgian united nations command,1
+venus genetrix,1
+sayesha saigal,14
+inverse dynamics,2
+national constitutional assembly,1
+honey bear,4
+certosa di pavia,2
+selective breeding,31
+let your conscience be your guide,1
+han hyun jun,1
+closed loop,8
+template talk golf major championships master,1
+twin oaks community virginia,1
+red flag,3
+housing authority of new orleans,2
+joice heth,4
+toñito,1
+ivan pavlov,2
+madanapalle,4
+ptat,1
+renger van der zande,1
+anaerobic metabolism,2
+patrick osullivan,1
+shirakoya okuma,1
+permian high school,9
+thomas h ford,1
+southfield high school,1
+religion in kuwait,2
+nathrop colorado,1
+hefner hugh m,1
+whitney bashor,1
+pope shenouda iii of alexandria,7
+thomas henderson,1
+tokka and rahzar,13
+windows thumbnail cache,3
+consumer council for water,1
+sake bombs and happy endings,1
+lothlórien,1
+the space bar,4
+sakuma rail park,1
+oas albay,3
+dan frankel,1
+cliff hillegass,1
+iron sky,12
+pentile matrix family,1
+oregon system,1
+california sea lion,7
+jeanneau,2
+meadowhall interchange,1
+lille catholic university,1
+nuñomoral,1
+vending machine,30
+xarelto,1
+jonbenét ramsey,3
+progresso castelmaggiore,1
+tacticity,6
+wing arms,1
+gag,2
+hank greenberg,8
+garda síochána,14
+puggy,1
+p sainath,1
+the year of living dangerously,9
+army reserve components overseas training ribbon,1
+hmas nestor,1
+john beckwith,1
+florida constitution,2
+yonne,3
+benoît richaud,1
+mamilla pool,2
+gerald bull,14
+david halberstam,12
+my fair son,2
+ncaa division iii womens golf championships,1
+anniela,1
+king county,1
+kamil jankovský,1
+synaptic,3
+rab,6
+switched mode regulator,1
+history of biochemistry,1
+halaf,2
+henry colley,1
+co postcode area,3
+social finance uk,1
+cercospora,2
+the dao,1
+unité radicale,2
+shinji hashimoto,3
+tommy remengesau,3
+isobel gowdie,2
+mys prasad,9
+national palace museum of korea,1
+basílica del salvador,2
+no stone unturned,2
+walton group,1
+foramen ovale,1
+slavic neopaganism,1
+iowa county wisconsin,3
+melodi grand prix junior,1
+jarndyce and jarndyce,3
+talagunda,1
+nicholas of autrecourt,1
+substitution box,3
+the power of the daleks,1
+real gas,6
+edward w hincks,1
+kangxi dictionary,5
+natural world,1
+h h asquith,21
+francis steegmuller,1
+sasha roiz,3
+media manipulation,1
+looking for comedy in the muslim world,2
+bytown,4
+previsualization,1
+rita ora discography,11
+kiersey oklahoma,1
+henry greville 3rd earl of warwick,1
+draft,4
+phenolate,1
+i believe,1
+virologist,1
+relief in abstract,1
+eastern medical college,1
+purveyance,2
+ascending to infinity,2
+sportstime ohio,2
+church of wells,1
+ivory joe hunter,1
+wayne mcgregor,2
+luna 17,4
+viscount portman,2
+wikipedia talk wikipedia signpost/2009 07 27/technology report,1
+negramaro,1
+barking owl,2
+i need you,2
+brockway mountain drive,1
+template talk albatros aircraft,1
+future shock,11
+china national highway 317,1
+laurent gbagbo,7
+plum pudding model,18
+league of the rural people of finland,1
+dundees rising,1
+nikon f55,1
+olympic deaths,5
+gemma jones,19
+hafsa bint al hajj al rukuniyya,1
+personal child health record,1
+logic in computer science,11
+bhyve,3
+hothouse,1
+log house,6
+library of celsus,2
+the lizzie bennet diaries,1
+leave this town the b sides ep,1
+estimated time of arrival,8
+chariotry in ancient egypt,2
+american precision museum,1
+dimos moutsis,1
+scriptlet,1
+something in the wind,1
+sharka blue,1
+time on the cross the economics of american negro slavery,1
+tomislav kiš,1
+khalid islambouli,7
+bankruptcy abuse prevention and consumer protection act,7
+gračanica bosnia and herzegovina,2
+jungs theory of neurosis,5
+mgm animation,1
+soviet support for iran during the iran–iraq war,3
+native american,1
+template talk nigeria squad 1994 fifa world cup,1
+norwegian lutheran church,4
+adia barnes,1
+coatings,1
+mehdi hajizadeh,1
+the dead matter cemetery gates,1
+fuzzy little creatures,1
+waje,7
+anji,1
+heinz haber,1
+turkish albums chart,1
+sebastian steinberg,1
+price fixing cases,2
+bellator 48,1
+edgar r champlin,1
+otto hermann leopold heckmann,1
+bishops stortford fc,4
+stern–volmer relationship,6
+morgan quitno,2
+five star general,1
+iso 13406 2,1
+black prince,11
+leopard kung fu,1
+felix wong,5
+mary claire king,6
+alvar lidell,1
+playonline,1
+infantry branch,1
+andrew pattison,1
+john turmel,1
+kent,74
+edwin palmer hoyt,1
+captivity narratives,1
+jaguar xj220,1
+hms tanatside,2
+new faces,2
+edward levy lawson 1st baron burnham,1
+samuel woodfill,3
+jewish partisans,9
+abandonware,16
+early islamic philosophy,2
+sleeper cell,5
+media of africa,2
+san andreas,3
+luxuria,2
+egon hostovský,3
+pelagibacteraceae,1
+martin william currie,1
+borescope,21
+narratives of islamic origins the beginnings of islamic historical writing,1
+lecompton constitution,2
+axé bahia,2
+paul goodman,1
+template talk washington nationals roster navbox,1
+a saucerful of secrets,2
+david carol macdonnell mather,1
+portal buddhism,3
+florestópolis,1
+alecs+golf+ab,1
+bank alfalah,1
+frank pellegrino,3
+loutre,1
+erp4it,2
+monument to joe louis,2
+witch trial of nogaredo,1
+sabrina santiago,2
+no night so long,3
+helena carter,1
+renya mutaguchi,3
+yo yogi,4
+bolivarian alliance for the americas,3
+cooper boone,1
+uss iowa,24
+mitsuo iso,2
+cranberry,1
+batrachotomus,1
+richard lester,5
+bermudo pérez de traba,1
+rosser reeves ruby,1
+telecommunications in morocco,4
+i a richards,1
+nidhal guessoum,1
+lilliefors test,6
+the silenced,5
+mambilla plateau,1
+sociology of health and illness,3
+tereza chlebovská,2
+bismoll,3
+kim suna,1
+scream of the demon lover,1
+joan van ark,7
+intended nationally determined contributions,6
+dietary supplement,16
+last chance mining museum,1
+savoia marchetti s65,1
+if i can dream,1
+maharet and mekare,4
+nea anchialos national airport,2
+american journal of digestive diseases,1
+chance,2
+lockheed f 94c starfire,1
+the game game,1
+kuzey güney,3
+semmering base tunnel,1
+three mile island,1
+evaluation function,1
+robert mckee,4
+carmelo soria,1
+moneta nova,1
+pīnyīn,1
+international submarine band,3
+elections in the bahamas,5
+powell alabama,1
+kmgv,1
+charles stuart duke of kendal,2
+echo and narcissus,7
+trencrom hill,1
+ashwini dutt,1
+the herzegovina museum,1
+liverpool fc–manchester united fc rivalry,12
+kerber,1
+flakpanzer 38,8
+demographics of bihar,2
+rico reeds,1
+vandenberg afb space launch complex 3,1
+wiesendangen,1
+lamm,1
+allen doyle,2
+anusree,5
+broad spectrum,1
+bay middleton,2
+connect savannah,1
+history of immigration to canada,22
+waco fm,3
+nakano takeko,1
+murnau am staffelsee,2
+minarchy,1
+haymans dwarf epauletted fruit bat,1
+brachyglottis repanda,1
+associative,1
+mississippi aerial river transit,1
+stefano siragusa,2
+gregor the overlander,3
+marine raider,1
+pogorzans,1
+sportcity,2
+garancahua creek,1
+vincent dimartino,3
+ninja,2
+natural history museum of bern,1
+revolutionary catalonia,4
+chiayi,1
+alix strachey,3
+looe island,1
+college football usa 96,1
+off peak return,1
+minsk 1 airport,1
+evangelical lutheran church in burma,2
+riemann–roch theorem,1
+the comic strip,2
+vladimir istomin,1
+america again,2
+brown treecreeper,1
+american high school,1
+powerglide,2
+oolitic limestone,1
+daz1,1
+jarrow vikings,1
+pierre philippe thomire,1
+dorothy cadman,1
+gaston palewski,3
+twin river bridges,1
+im yours,1
+ambrose dudley 3rd earl of warwick,3
+ssim,2
+original hits,1
+cosmonaut,9
+special educational needs and disability act 2001,4
+will you speak this word,1
+history of wolverhampton wanderers fc,1
+don lawrence,1
+tokyo metropolitan museum of photography,1
+orduspor,1
+john lukacs,3
+patrice collazo,1
+lords resistance army insurgency,5
+ronald "slim" williams,5
+drivin for linemen 200,1
+nicolò da ponte,1
+bucky pope,1
+ewing miles brown,2
+ugly kid joe,28
+american flight 11,1
+louzouer,1
+district hospital agra,1
+jessica jane applegate,1
+sexuality educators,1
+serie a scandal of 2006,1
+at war with reality,1
+stephen wiltshire,13
+vechigen switzerland,1
+rikki clarke,3
+rayakottai,1
+permanent magnet electric motor,1
+qazi imdadul haq,1
+plywood,49
+ntr telugu desam party,1
+skin lightening,1
+royal natal national park,1
+uss mcdougal,2
+queen of the sun,1
+karanjachromene,1
+on 90,1
+enrique márquez,1
+siegfried and roy,1
+city manager,6
+wrdg,1
+why i am not a christian,3
+protein coding region,1
+royal bank of queensland gympie,1
+british invasions of the river plate,2
+yasufumi nakanoue,1
+magnetic man,1
+kickback,3
+tillandsia subg allardtia,1
+north american nr 349,1
+edict of amboise,1
+st andrew square edinburgh,2
+flag of washington,2
+timeless,2
+new york state route 125,3
+fudge,3
+single entry bookkeeping system,5
+refractive surgery,8
+bi monthly,1
+park high school stanmore,1
+norton anthology of english literature,1
+michael wines,1
+gaff rig,1
+kosmos 1793,1
+major facilitator superfamily,2
+talpur dynasty,1
+byron bradfute,1
+quercitello,1
+rcmp national protective security program,1
+ann kobayashi,1
+recurring saturday night live characters and sketches,3
+abraham hill,1
+nagapattinam district,4
+pidgeon,3
+mycalessos,1
+technical university of hamburg,1
+electric shock&ei=ahp0tbk0emvo gbe v2bbw&sa=x&oi=translate&ct=result&resnum=2&ved=0ceaq7gewaq&prev=/search?q=electric+shock&hl=da&biw=1024&bih=618&prmd=ivns,2
+aim 54 phoenix,18
+undercut,5
+gokhale memorial girls college,1
+digital penetration,19
+centre for peace studies tromsø,1
+richie williams,1
+walloon region,1
+albany city hall,2
+maxine carr,4
+anglosphere,18
+effect of world war i on children in the united states,1
+josh bell,1
+german thaya,1
+brian murphy,3
+marguerite countess of blessington,1
+leak,1
+bubble point,5
+international federation of human rights,1
+clubcorp,2
+greater philadelphia,1
+daniel albright,1
+macas,1
+roses,4
+woleu ntem,1
+shades of blue,1
+say aah,2
+curtiss sbc,1
+ion andone,1
+firstborn,1
+marringarr language,2
+ann e todd,1
+native american day,4
+stand my ground,1
+bavington,1
+classification of indigenous peoples of the americas,2
+always,6
+leola south dakota,1
+psycilicibin,2
+roy rogers,1
+marmalade,1
+national prize of the gdr,1
+shilp guru,1
+m2 e 50,1
+jorge majfud,2
+cutter and bone,1
+william steeves,1
+lisa swerling,2
+grace quigley,5
+telecommunications in yemen,1
+rarotonga international airport,7
+cycling at the 2010 central american and caribbean games,2
+mazda b3000,1
+hanwencun,1
+adurfrazgird,1
+ivan ivanov vano,1
+yhwh,1
+qarshi,4
+oshibori,2
+uppada,1
+iain clough,1
+painted desert,7
+tugzip,1
+my little pony fighting is magic,143
+pantheon,2
+chinese people in zambia,1
+yves saint laurent,3
+texas helicopter m79t jet wasp ii,1
+forever reign,1
+charlotte crosby,32
+ealdormen,9
+copper phosphate,2
+mean absolute difference,5
+hôtel de soubise,5
+josh rees,2
+non commissioned officer,70
+gb jones,1
+im feeling you,2
+book of shadows,9
+brain trauma,1
+sulpitius verulanus,1
+vikranth,5
+space adaptation syndrome,6
+united states presidential election in hawaii 1988,1
+joe garner,4
+river suir bridge,2
+the beach boys medley,1
+joyce castle,1
+christophe wargnier,1
+ik people,2
+sketch show,1
+buena vista police department,1
+file talk layzie bone clevelandjpg,1
+gillian osullivan,3
+prince albert of saxe coburg and gotha,2
+berean academy,1
+motorcraft quality parts 500,1
+frederick law olmsted,21
+born this way,9
+sterling virginia,4
+if wishes were horses beggars would ride,1
+section mark,1
+tapi,1
+navy cross,1
+housekeeper,1
+gian battista marino,1
+planá,1
+chiromantes haematocheir,1
+colonial life & accident insurance company,4
+aduana building,2
+kim johnston ulrich,1
+berkelium 254,1
+m&t bank corp,2
+sit up,1
+sheknows,1
+phantom lady,1
+bruce kamsinky,1
+commercial drive,1
+chinese people in the netherlands,1
+sylvia young theatre school,4
+influenza a virus subtype h2n3,1
+dracut,2
+nate webster,1
+vila velebita,1
+uaz patriot,4
+democratic unification party,1
+alexander slidell mackenzie,1
+portland mulino airport,1
+first person shooter,2
+the temporary widow,1
+terry austin,1
+the foremans treachery,1
+hms blenheim,1
+sodium dichloro s triazinetrione,1
+kurt becher,1
+cumberland gap tn,1
+newton cotes,1
+daphne guinness,6
+internal tide,1
+god and gender in hinduism,2
+howlin for you,1
+stellarator,14
+cavea,3
+faye ginsburg,1
+lady cop,3
+template talk yugoslavia squad 1986 fiba world championship,1
+solidarity economy,1
+second presidency of carlos andrés pérez,1
+bora bora,71
+xfs,1
+christina bonde,1
+agriculture in australia,20
+scenic drive,1
+richard mantell,1
+motordrome,1
+broadview hawks,1
+misty,2
+international bank of commerce,2
+istanbul sapphire,5
+changkat keruing,1
+the hotel inspector unseen,1
+tharwa australian capital territory,2
+strauss,2
+shock film,1
+ulick burke 1st marquess of clanricarde,2
+valencia cathedral,5
+kay bojesen,1
+palogneux,1
+texas beltway 8,1
+jackie walorski,7
+capital punishment in montana,1
+byte pair encoding,2
+upper deerfield township new jersey,2
+lucca comics & games,1
+lee chae young,1
+czar alexander ii,1
+kool ad,6
+leopold van limburg stirum,1
+john dunn,1
+policeman,2
+what dreams may come,3
+grant ginder,1
+chieverfueil,2
+long island express,1
+malmö sweden,2
+song for my father,1
+see saw,2
+jean jacques françois le barbier,5
+do rag,11
+dsb bank,2
+davical,6
+cervical cap,1
+gershon yankelewitz,1
+the last hurrah,4
+category talk educational institutions established in 1906,1
+tour pleyel,1
+león klimovsky,1
+phyoe phyoe aung,1
+phil sawyer,2
+android app //orgwikipedia/http/enmwikipediaorg/wiki/swiftkey,1
+deontological,3
+juan dixon,12
+robert pine,4
+alexander tilloch galt,2
+common tailorbird,12
+derailed,7
+mike campbell,3
+terminator 2 3 d battle across time,3
+technische universität münchen,4
+baloana,1
+echis leucogaster,1
+lahore pigeon,1
+william de beauchamp 9th earl of warwick,2
+erin go bragh,14
+economics u$a,1
+villafranca montes de oca,1
+pope eusebius,2
+martin kruskal,1
+félix de blochausen,1
+jeff jacoby,1
+mark krein,2
+travis wester,2
+fort louis de la louisiane,1
+weddingwire,2
+ping,54
+don swayze,8
+steve hamilton,3
+rhenish,1
+winrar,3
+births in 1561,4
+copyright law of the netherlands,2
+floodland,9
+tamil nadu tourism development corporation,1
+dolls house,1
+chkrootkit,1
+search for the hero,1
+avenal,1
+tini,2
+patamona,1
+aspendos international opera and ballet festival,2
+felix cora jr,5
+yellow cardinal,2
+antony jay,1
+conda,1
+a tramp shining,1
+william miller,1
+holomictic lake,2
+growler,2
+the violence of summer,1
+meerschaum,3
+cd138,1
+karl friedrich may,1
+history of iraq,2
+henry ford,139
+rumwold,1
+beatrice di tenda,1
+blaze,1
+nick corfield,1
+walt longmire,5
+eleazar maccabeus,1
+business edition,1
+karl oyston,4
+gypsy beats and balkan bangers,1
+fa premier league 2004 05,1
+agawan radar bomb scoring site,1
+the hall of the dead,1
+combat training centre,1
+moroccan portuguese conflicts,2
+pokipsy,1
+minor characters in csi crime scene investigation,1
+miguel molina,1
+buckypaper,2
+magazine,4
+forget about it,2
+marco schällibaum,1
+r d smith,1
+nfl playoff results,2
+four score,1
+centenary bank,2
+london borough of camden,12
+bhumij,1
+counter reformation/trackback/,1
+billy volek,1
+cover song,1
+awang bay,1
+douglas fitzgerald dowd,3
+architecture of ancient greece,5
+ny1,2
+academy award for best visual effects,3
+history of the mbta,2
+triangle group,1
+charles r fenwick,1
+berenice i of egypt,1
+window detector,1
+corruption perception index,1
+leffrinckoucke,1
+lee anna clark,1
+burndy,2
+inset day,2
+american association of motor vehicle administrators,1
+ckm matrix,1
+angiopoietin 1,1
+steven marsh,1
+open reading frame,27
+telesystems,1
+pastoral poetry,1
+west wycombe park,2
+lithium,7
+nogales international airport,1
+wajków,1
+sls 1,1
+trillo,2
+max s,1
+verndale,1
+yes sir i can boogie,1
+blog spam,10
+daniel veyt,1
+william brown,3
+takami yoshimoto,1
+josh greenberg,4
+geoffrey heyworth 1st baron heyworth,1
+medeina,3
+anja steinlechner,1
+riviera beach florida,2
+gerris wilkinson,1
+north american lutheran church,1
+paul dillett,11
+proto euphratean language,1
+best selling books,2
+pumpellyite,1
+business objects,1
+fodor,2
+xanadu,3
+london river,1
+draft juan de orduña,2
+barriemore barlow,3
+jew harp,1
+birmingham,1
+titus davis,1
+march 2012 gaza–israel clashes,1
+energy demand management,2
+aquarium of the americas,3
+tto,1
+l h c tippett,1
+optical fiber,88
+onești,2
+stanley ntagali,1
+prussian blue,1
+bill kovach,2
+hip pointer,3
+alessandra amoroso,4
+fleet racing,1
+navy maryland rivalry,1
+cornering force,1
+the mighty quest for epic loot,5
+katalyst,2
+the beef seeds,1
+shack out on 101,1
+aircraft carrier operations,1
+overseas province,2
+institute of state and law,1
+light truck,5
+plastics in the construction industry,2
+little zizou,2
+congenic,2
+adriaen van utrecht,1
+brian mcgrath,3
+parvati,1
+jason gwynne,1
+kphp,1
+miryusif mirbabayev,1
+kōriyama castle,3
+the making of a legend gone with the wind,2
+shot traps,1
+awa tag team championship,1
+littlebourne,2
+franchot tone,4
+john dudley 2nd earl of warwick,2
+mass spec,1
+final fantasy vi,44
+gerry ellis,1
+adon olam,3
+man 24310,1
+p n okeke ojiudu,1
+unqi,1
+snom,1
+bruce bagemihl,1
+category talk animals described in 1932,1
+metalist oblast sports complex,1
+colley harman scotland,1
+suka,1
+anita sarkeesian,81
+kazakhstan national under 17 football team,1
+ym,2
+matt barnes,1
+tour phare,1
+bellus–claisen rearrangement,2
+turkey at the 2012 summer olympics,1
+irréversible,32
+umbilical nonseverance,1
+wood stave,1
+indian pentecostal church of god,1
+camponotus nearcticus,3
+john tesh,13
+syncline,4
+skins,50
+kelsey manitoba,1
+alkayida,2
+polyglotism,17
+forensic statistics,2
+ram vilas sharma,8
+pearl jam,71
+dj max fever,1
+islamic view of miracles,5
+kds,1
+alabama cavefish,1
+johanna drucker,1
+tom wolk,4
+rottenburg,2
+goshen connecticut,2
+maker media,1
+morphett street adelaide,1
+keystone hotel,1
+baseball hall of fame balloting 2005,1
+gongzhuling south railway station,1
+ss charles bulfinch,1
+sig mkmo,1
+cartman finds love,2
+embassy of syria in washington dc,1
+charles prince of wales,175
+teachings of the prophet joseph smith,1
+charles iv,1
+alethea steven,1
+type i rifle,2
+a peter bailey,1
+brain cancer,1
+eric l clay,2
+jett bandy,1
+moro rebellion,9
+eustachów,1
+avianca el salvador,2
+dont stop the party,4
+reciprocal function,1
+dagmar damková,1
+hautmont,1
+penguin english dictionary,2
+waddie mitchell,1
+technician fourth grade,3
+hot girls in love,1
+critérium du dauphiné,59
+love song,2
+roger ii,2
+whitbread book award,1
+thomas colepeper 2nd baron colepeper,2
+a king and no king,1
+big fish & begonia,5
+mayville new york,2
+molecularity,1
+ed romero,1
+one watt initiative,3
+jeremy hellickson,2
+william morgan,1
+giammario piscitella,1
+eastern lesser bamboo lemur,1
+padre abad district,1
+don brodie,1
+facts on the ground,1
+undeniable evolution and the science of creation,1
+john of giscala,1
+bryce harper,45
+gabriela irimia,1
+empire earth mobile,1
+the queen vic,1
+helen rowland,1
+mixed nuts,5
+malacosteus niger,2
+george r r martin/a song of ice and fire,1
+brock osweiler,11
+tough,1
+outline of agriculture,4
+sea wolf,1
+mo vaughn,4
+the brood of erys,1
+composite unit training exercise,1
+isabella acres,4
+the jersey,5
+coal creek bridge,1
+habana libre,1
+nicole pulliam,1
+john shortland,1
+daniel pollen,1
+magic kit,1
+baruch adonai l&,1
+a daughters a daughter,2
+laughlin nevada,11
+tubercule,1
+louis laurie,1
+internet boom,3
+conversion of paul,1
+comparison of software calculators,1
+choctaw freedmen,2
+josh eady,1
+hôpital charles lemoyne,2
+u mobile,2
+john tomlinson,1
+baré esporte clube,2
+tuğçe güder,2
+highams park railway station,4
+newport east,1
+clothing industry,6
+scott rosenberg,6
+my 5 wives,2
+matt godfrey,1
+port ellen,2
+winecoff hotel fire,1
+fide world chess championship 2005,2
+lara piper,1
+the little mermaid,1
+foxmail,6
+penn lyon homes,1
+stockholm opera,1
+american journal of theology,1
+bernard gorcey,3
+rodger collins,1
+clarkeulia sepiaria,1
+korean era name,3
+melide ticino,1
+unknown to no one,1
+asilinae,1
+scânteia train accident,1
+parti de la liberté et de la justice sociale,1
+falkland islands sovereignty dispute,13
+castile,10
+french battleship flandre,1
+nils taube,1
+anisa haghdadi,1
+william tell told again,2
+magister,3
+zgc 7,1
+national agricultural cooperative marketing federation of india,3
+les bingaman,1
+chebfun,1
+portal current events/august 2014,2
+eparchy of oradea mare,1
+tempo and mode in evolution,2
+seili,1
+boniface,3
+supportersvereniging ajax,1
+support team,1
+lactometer,1
+twice as sweet,1
+spruce pine mining district,2
+banknotes of the east african shilling,1
+cerebral cortex,3
+tagalogs,1
+german diaspora,8
+grammelot,1
+max a,1
+category talk vienna culture,1
+cheung kong graduate school of business,1
+three certainties,1
+multani,3
+barry callebaut,15
+joanne mcneil,1
+z grill,4
+commonwealth of australia constitution act 1900,1
+ganzorigiin mandakhnaran,1
+peter h schultz,1
+ea pga tour,3
+scars & memories,1
+exodus from lydda,1
+states reorganisation act 1956,4
+guy brown,1
+horsebridge,1
+arthur mafokate,1
+aldus manutius,5
+american daylight,3
+jean chaufourier,2
+edmond de caillou,1
+hms iron duke,9
+displeased records,1
+quantum turing machine,3
+ncert textbook controversies,2
+dracs,1
+beyrouth governorate,1
+staphylococcus caprae,1
+tankard,2
+surfaid international,1
+hohenthurn,2
+mission x 41,1
+professional wrestling hall of fame,2
+george mountbatten 4th marquess of milford haven,2
+athletics at the 2012 summer paralympics womens club throw f31 32/51,1
+knots and crosses,1
+edge vector,1
+philippe arthuys,1
+baron raglan,1
+odell beckham jr,3
+elfriede geiringer,1
+hyflux,1
+author level metrics,2
+ieee fellow,1
+pori brigade,3
+polyphenol antioxidant,1
+the brothers,8
+kakaji Ōita,1
+shyam srinivasan,2
+shahid kapoor,88
+chuckie williams,1
+colonial,4
+roman spain,1
+convolvulus pluricaulis,1
+william j burns international detective agency,1
+accessibility for ontarians with disabilities act 2005,1
+linguist,1
+agonist,2
+xiaozi,1
+holker hall,1
+novatium,1
+alois jirásek,1
+lesser crested tern,1
+names of european cities in different languages z,1
+hydrogen cooled turbogenerator,2
+indian airlines flight 257,1
+united states attorney for the northern district of indiana,1
+this is us,11
+transaction capabilities application part,1
+culiacán,6
+hash based message authentication code,65
+heinz murach,1
+dual citizen,2
+zhizn’ za tsarya,1
+gabriel taborin technical school foundation inc,1
+deaths in july 1999,1
+aponi vi arizona,1
+amish in the city,2
+goodbye cruel world,1
+st augustine grass,10
+moesi,1
+violette leduc,3
+methyl formate,9
+you walk away,1
+the traveler,1
+bond,89
+moa cuba,3
+hebrew medicine,1
+women in the russian and soviet military,2
+help log,2
+cuillin,5
+back fire,14
+salesrepresentativesbiz,1
+hogsnort rupert,1
+dwarf minke whale,1
+embassy of albania ottawa,1
+cotai water jet,1
+st lucie county florida,8
+wesselman,1
+american indian art,1
+richard arkless,1
+trolleybuses in bergen,1
+vama buzăului,1
+far east movement,9
+threes a crowd,1
+insane,3
+linux technology center,4
+patty duke,24
+smuckers,1
+kapalua,1
+amf futsal world cup,5
+umes chandra college,1
+jnanappana,2
+bar bar bar,1
+beretta m951,2
+libertarian anarchism,1
+fart proudly,4
+peyton place,5
+phase detection autofocus,1
+cavalry in the american civil war,9
+class stratification,1
+battle of cockpit point,1
+regiment van heutsz,2
+ana rivas logan,1
+nenya,1
+westland wah 64 apache,1
+roslyn harbor new york,3
+august wilhelm von hofmann,1
+professional baseball,2
+douglas feith,1
+pogrom,21
+aušra kėdainiai,1
+pseudopeptidoglycan,4
+arquà petrarca,1
+wayampi,1
+conservative government 1866 1868,1
+world naked bike ride,28
+fruitvale oil field,2
+shuttle buran,1
+robert c pruyn,1
+totem,1
+megalotheca,1
+nkechi egbe,1
+james p comeford,1
+heavens memo pad,7
+cauca valley,1
+jungfraujoch railway station,2
+seo in guk,24
+bold for delphi,1
+multiple frames interface,1
+zhenli ye gon,6
+kyabram victoria,1
+two stars for peace solution,1
+couette flow,9
+new formalism,2
+template talk 1930s comedy film stub,1
+template talk scream,1
+joona toivio,4
+iaaf silver label road race,1
+super bowl xxviii,5
+i aint never,1
+paul little racing,1
+jacobite rising of 1715,3
+katherine archuleta,1
+programmable logic device,12
+footsteps of our fathers,2
+once upon a tour,1
+tauck,1
+budapest memorandum on security assurances,5
+prostitution in chad,2
+bebedouro,2
+vice,2
+madredeus,1
+p diddy,1
+princess alice of the united kingdom,20
+jerry hairston jr,1
+neo noir,3
+self evaluation motives,1
+relativity the special and the general theory,2
+the sign of four,3
+kevin deyoung,1
+robin long,1
+mokshaa helsa,1
+nagaon,1
+aniceto esquivel sáenz,1
+sda,2
+german battlecruiser gneisenau,1
+assisted reproductive technology,12
+cmmg,1
+vision of you,1
+keshia chanté discography,1
+biofuel in the united kingdom,1
+katinka ingabogovinanana,1
+hutt valley,1
+garwol dong,1
+tunceli province,3
+edwin bickerstaff,1
+halloween 3 awesomeland,1
+canadian records in track and field,1
+ubisoft são paulo,1
+midstream,16
+jethro tull,4
+childhoods end,55
+ss rohilla,1
+lagranges four square theorem,6
+bucky pizzarelli,3
+jannik bandowski,80
+guðni Ágústsson,1
+multidimensional probability distribution,1
+brno–tuřany airport,2
+broughtonia,5
+cold hands warm heart,1
+simone biles,32
+bf homes parañaque,2
+akaflieg köln ls11,3
+street fighter legacy,2
+beautiful kisses,1
+first modern olympics,1
+macbook air,1
+dublab,1
+silent night deadly night,6
+earth defense force 2025,2
+grant township carroll county iowa,1
+gary williams,1
+malmö aviation,1
+geographical pricing,2
+anaheim memorial medical center,1
+mary+mallon,1
+henry a byroade,1
+wawasan 2020,4
+eurovision dance contest,6
+lydia polgreen,1
+pilsen kansas,1
+colin sampson,1
+neelamegha perumal temple,1
+james bye,2
+canadian federation of agriculture,1
+f w de klerk,34
+bob casey jr,3
+northport east,1
+elian gonzalez affair,1
+aleksei bibik,1
+anthony dias blue,1
+pyaar ke side effects,4
+fusako kitashirakawa,1
+cal robertson,4
+shandong national cultural heritage list,1
+police story 3 super cop,5
+the third ingredient,3
+dean horrix,1
+pico el león,1
+cesar chavez street,1
+prospered,1
+children in cocoa production,5
+gervase helwys,1
+binary digit,1
+kovai sarala,4
+mathematics and music,1
+macroglossum,1
+f gary gray,21
+broadsoft,2
+cachan,4
+bukkake,21
+church of st margaret of scotland,1
+christopher cockerell,3
+amsterdam oud zuid,1
+county of bogong,1
+intel mobile communications,1
+the legend of white fang,1
+millwright,19
+will buckley,1
+bill jelen,2
+template talk san francisco 49ers coach navbox,1
+amalia garcía,1
+because he lives,1
+air charts,1
+stade edmond machtens,1
+henry stommel,1
+dxgi,1
+misr el makasa sc,1
+chad price,2
+carl henning wijkmark,1
+acanthogorgiidae,1
+diqduq,1
+prelog strain,2
+crispin the cross of lead,4
+avraham adan,2
+barbershop arranging,1
+free x tv,1
+eric guillot,1
+kht,1
+never a dull moment,1
+lwów school of mathematics,1
+sears centre,3
+chin state,6
+van halen 2007 2008 tour,1
+robert weinberg,3
+fierté montréal,2
+vince jack,1
+heikki kuula,1
+architecture of the republic of macedonia,1
+glossary of education terms,1
+aleksandra szwed,1
+military history of europe,3
+exeter central railway station,1
+staroselye,1
+lee thomas,7
+saint peters square,2
+romanization of hispania,2
+file talk dodecahedrongif,1
+signed and sealed in blood,8
+colleges of worcester consortium,1
+district electoral divisions,1
+galkot,1
+king África,3
+monetary policy,57
+brp ang pangulo,2
+battle of mạo khê,1
+air tube,1
+ruth ashton taylor,2
+keith jensen,1
+headland alabama,1
+willie loomis,1
+interactive data extraction and analysis,2
+georgetown city hall,2
+chuck es in love,2
+weeksville brooklyn,1
+anatoly sagalevich,2
+browett lindley & co,1
+barnawartha victoria,1
+pop,2
+black balance,2
+aceratorchis,1
+emmeline pethick lawrence baroness pethick lawrence,1
+osso buco,1
+herminie cadolle,2
+telegram & gazette,2
+le van hieu,1
+pine honey,2
+nexvax2,1
+leicester north railway station,1
+jacqueline foster,1
+bill handel,3
+nizami street,1
+radke,1
+bob mulder,1
+ambroise thomas,4
+carles puigdemont i casamajó,1
+callable bond,6
+tesco metro,2
+mohan dharia,1
+great hammerhead,12
+vinko coce,3
+john mayne,1
+cobb cloverleaf,1
+uhlan,10
+giulio migliaccio,1
+belmont university,6
+rinucumab,1
+kearny high school,1
+chūgen,1
+stages,2
+boar%27s head carol,1
+knight of the bath,1
+ayres thrush,7
+sing hallelujah,1
+the tender land,2
+wholesale banking,1
+jean jacques perrey,5
+maxime bossis,2
+sherman records,1
+alan osório da costa silva,1
+fannie willis johnson house,1
+blacks equation,2
+levinthals paradox,2
+thomas scully,2
+necron,3
+university of alberta school of business,5
+lake shetek,1
+toby maduot,1
+gavriil golovkin,1
+sweetwater,3
+atlantic revolutions,2
+jaime reyes (comics,1
+kajang by election 2014,1
+mycotoxigenic,1
+san marco altarpiece,2
+line impedance stabilization network,2
+santiago hernández,1
+jazzland,3
+host–guest chemistry,4
+giovanni florio,2
+st marylebone school,1
+acqua fragile,1
+the horse whisperer,10
+don francis,1
+mike molesevich,1
+brad wright,1
+north melbourne football club,3
+brady dragmire,1
+margaret snowling,2
+wing chun terms,4
+mckey sullivan,1
+derek ford,1
+cache bus,1
+bernie grant arts centre,2
+amata francisca,1
+sinha,2
+larissa loukianenko,1
+oceans apart&sa=u&ved=0ahukewjw4n6eqdblahun7gmkhxxebd8qfgg4mag&usg=afqjcnhhjagrbamjgaxc7rpsso4i9z jgw,1
+anemone heart,2
+alison mcinnes,1
+juan lindo,1
+mahesh bhupati,1
+baháí faith in taiwan,5
+cinema impero,1
+template talk rob thomas,1
+likin,1
+science & faith,1
+fort saint elmo,3
+delhi kumar,6
+juha lallukka,1
+situational sexual behavior,2
+milligan indiana,1
+william em lands,1
+karl anselm duke of urach,2
+hérold goulon,1
+vedic mathematics,20
+move to this,1
+koussan,1
+floored,1
+raghu nandan mandal,1
+angels gods secret agents,1
+orthogonal,2
+the little house on the prairie,1
+chilean pintail,1
+guardian angel,2
+st leonard maryland,1
+green parties in the united kingdom,1
+time to say goodbye,1
+alba michigan,2
+harbourfront centre,1
+corner tube boiler,1
+consensus government,1
+ppru 1,1
+corporate anniversary,4
+sazerac company,5
+kyle friend,1
+bmw k1100lt,1
+pergola marche,1
+commonwealth of kentucky,2
+taiwan passport,2
+clare quilty,1
+domenico caprioli,1
+frank m hull,1
+cheng sui,2
+nazi board games,3
+spark bridge,1
+derrick thomas,6
+wunnumin 1,1
+emotion remixed +,4
+brian howard dix,2
+brigalow queensland,2
+burgi dynasty,1
+apolonia supermercados,1
+brandon lafell,2
+one day,24
+nara period,9
+template talk the land before time,1
+assyrians in iraq,1
+trade union reform and employment rights act 1993,2
+template talk evansville crimson giants seasons,1
+boys be smile / 目覚めた朝にはきみが隣に,2
+kapuloan sundha kecil,1
+human impact of internet use,1
+kolkata metro line 2,3
+saint pardoux morterolles,1
+carfin grotto,2
+samuel johnson prize,3
+french royal family,1
+android app //orgwikipedia/http/enmwikipediaorg/wiki/victoria park,1
+mazda xedos 9,1
+măiestrit,1
+petroleum economist,2
+penetration,2
+adrian rawlins,8
+plutonium 239,11
+culture of montreal,1
+british germans,2
+warszawa wesoła railway station,1
+lorenzo di bonaventura,6
+military ranks of estonia,1
+uss flint,8
+arthur f defranzo,1
+sadeh,1
+jammu and kashmir,3
+igor budan,2
+charmila,2
+choi,1
+mohammed ali khan walajah,1
+sourabh varma,1
+after here through midland,1
+martyn day,1
+justin larouche,1
+illinoiss 6th congressional district,4
+jackson wy,1
+tyson apostol,4
+mitch morse,1
+robert davila,1
+canons regular of saint john cantius,1
+giant girdled lizard,2
+cascade volcanoes,5
+fools day,1
+cordyline indivisa,1
+pueraria,2
+swiss folklore,4
+meretz,3
+united states senate elections 1836 and 1837,1
+baby i need your love/ easy come easy go,1
+butrus al bustani,2
+the lion the lamb the man,1
+rushikulya,1
+brickworks,3
+alliance party of kenya,1
+ludlow college,1
+internationalism,11
+ernest halliwell,1
+constantine phipps 1st marquess of normanby,1
+kari ye bozorg,1
+signal flow,4
+i beam,1
+devils lake,1
+union of artists of the ussr,2
+index of saint kitts and nevis related articles,1
+ethernet physical layer,18
+dimensional analysis,16
+anatomical directions,2
+supreme court of guam,1
+sentul kuala lumpur,2
+ducefixion,1
+red breasted merganser,4
+reservation,3
+in the land of blood and honey,9
+kate spade,2
+albina airstrip,1
+kankakee,1
+servicelink,2
+castilleja levisecta,1
+tonmeister,2
+chanda sahib,1
+lists of patriarchs archbishops and bishops,1
+mach zehnder modulator,1
+giants causeway,79
+literal,7
+uss gerald r ford,1
+monster hunter portable 3rd,3
+bayern munich v norwich city,1
+banking industry,1
+prankton united,1
+st elmo w acosta,1
+speech disorder,9
+welcome to my dna,1
+nouriel roubini,6
+arthur kill,2
+bill grundy,7
+jake gyllenhaal,1
+world bowl 2000,1
+wnt7a,1
+pink flamingo,2
+tridentine calendar,1
+ray ratto,1
+f 88 voodoo,1
+super star,4
+ondřej havelka,1
+sophia dorothea of celle,12
+clavulina tepurumenga,1
+vampire bats,4
+ihsan,1
+ocotea foetens,1
+gannett inc,1
+kemira,4
+gre–nal,2
+farm bureau mutual,1
+pete fox,1
+let him have it,3
+backwoods home magazine,6
+te reo maori remixes,1
+hussain andaryas,1
+bagun sumbrai,1
+the westin paris – vendôme,4
+xochiquetzal,4
+players tour championship 2013/2014,1
+picnic,7
+josh elliott,5
+ernak,3
+gracias,1
+k280ff,1
+bandaranaike–chelvanayakam pact,1
+patrick baert,1
+nausicaä of the valley of the wind,33
+al jurisich,1
+twitter,230
+window,38
+the power hour,1
+duplex worm,1
+sonam bajwa,16
+baljit singh deo,1
+indian jews,1
+outline of madagascar,1
+outback 8,1
+dye fig,1
+british columbia recall and initiative referendum 1991,1
+felipe suau,1
+north perry ohio,1
+gilbeys gin,1
+philippe cavoret,1
+luděk pachman,1
+the it girl,1
+dragonnades,1
+rick debruhl,2
+xpath 20,2
+sean mcnulty,1
+william moser,1
+international centre for the settlement of investment disputes,1
+mendes napoli,2
+canadian rugby championship,1
+battle of maidstone,2
+boulevard theatre,2
+snow sheep,3
+penalty corner,1
+michael ricketts,5
+crocodile,2
+job safety analysis,5
+duffy antigen,1
+counties of virginia,1
+a place to bury strangers,5
+socialist workers’ party of iran,1
+wlw t,1
+core autosport,1
+west francia,10
+karen kilgariff,2
+pacific tsunami museum,1
+first avenue,1
+troubadour,1
+great podil fire,1
+chilean presidential referendum 1988,1
+pavol schmidt,1
+handguard,1
+crime without passion,1
+dio at donington uk live 1983 & 1987,1
+optic nerves,1
+wake forest school of medicine,1
+new jersey jewish news,2
+luke boden,2
+chris hicky,1
+beforu,2
+verch,1
+st roch,3
+civitas,1
+tmrevolution,3
+jamie spencer,1
+bond beam,1
+megan fox,4
+battle of bayan,1
+japan airlines flight 472,1
+yuen kay san,1
+the friendly ghost,1
+rice,14
+jack dellal,16
+lee ranaldo,9
+the overlanders,1
+earl castle stewart,5
+first down,1
+rheum maximowiczii,1
+washington state republican party,2
+ostwald bas rhin,1
+tennessee open,1
+kenneth kister,1
+ted kennedy,72
+preben elkjaer,1
+india reynolds,2
+santagata de goti,1
+henrietta churchill 2nd duchess of marlborough,1
+creteil,1
+ntt data,3
+zoot allures,4
+theatre of ancient greece,29
+bujinkan,6
+clube ferroviário da huíla,2
+nhn,4
+hp series 80,2
+interstate 15,4
+moszczanka,1
+lawnside school district,1
+virunga mountains,5
+hallway,1
+serb peoples radical party,1
+free dance,1
+mishawaka amphitheatre,1
+deerhead kansas,1
+utopiayile rajavu,1
+john w olver transit center,1
+futa tooro,1
+digoxigenin,5
+thomas schirrmacher,1
+twipra kingdom,1
+pulpwood,6
+think blue linux,1
+raho city taxi,1
+frederic remington art museum,1
+wajdi mouawad,1
+semi automatic firearm,12
+phyllis chase,1
+malden new york,1
+the aetiology of hysteria,2
+my maserati does 185,1
+friedrich wilhelm von jagow,1
+apne rang hazaar,1
+bór greater poland voivodeship,1
+india rubber,2
+bring your daughter to the slaughter,4
+yasser radwan,1
+kuala ketil,1
+notre dame de paris,1
+yuanjiang,1
+fengjuan,1
+tockenham,1
+transnistrian presidential election 1991,1
+gautami,28
+providenciales airport,1
+donald chumley,1
+middle finger,8
+calke abbey,4
+thou shalt not kill,1
+trail,7
+battle of dunkirk,43
+eyre yorke block,3
+mactan,3
+american ninja warrior,2
+nevel papperman,1
+ninja storm power rangers,1
+uss castle rock,1
+turcos,1
+philippine sea frontier,1
+irom chanu sharmila,7
+for the first time,2
+stian ringstad,1
+tréon,1
+hiro fujikake,1
+renewable energy in norway,4
+dedh ishqiya,18
+leucothoe,2
+ecmo,2
+knfm,1
+gangnam gu,1
+oadby town fc,1
+clamperl,2
+mummy cave,2
+kenneth d bailey,2
+peter freuchen,2
+dayanand bandodkar,2
+shawn crahan,16
+barbara trentham,2
+university of virginia school of nursing,1
+vöckla,1
+intuitive surgical inc,1
+cyncoed,4
+john l stevens,1
+daniel farabello,1
+trent harmon,5
+feroze gandhi unchahar thermal power station,1
+samuel powell,1
+pan slavic,1
+swimming at the 1992 summer olympics – womens 4 × 100 metre freestyle relay,1
+human behaviour,2
+siege of port royal,3
+eridug,1
+lafee,1
+north bethesda trail,1
+scheveningen system,1
+special penn thing,1
+pserimos,1
+pravda vítězí,1
+wiki dankowska,1
+transcript,13
+second inauguration of grover cleveland,1
+spent fuel,1
+ertms regional,2
+frederick scherger,1
+nivis,1
+herbert hugo menges,1
+kapitan sino,1
+samson,34
+minae mizumura,2
+gro kvinlog,1
+chasing shadows,2
+d j fontana,1
+massively multiplayer online game,27
+capture of new orleans,8
+meat puppet,1
+american pet products manufacturers association,3
+villardonnel,1
+sessile serrated adenoma,3
+patch products,1
+lodovico altieri,1
+portal,2
+jake maskall,4
+the shops at la cantera,8
+stage struck,5
+elizabeth m tamposi,2
+taylor swift,22
+forum spam,9
+barry cowdrill,3
+patagopteryx,2
+korg ms 2000,1
+hmas dubbo,2
+ss khaplang,2
+kevin kelly,1
+punk goes pop volume 5,3
+spurt,2
+bristol pound,5
+military history of finland during world war ii,10
+laguardia,1
+josé marcó del pont,1
+conditional expectation,18
+the beat goes on,1
+patricia buckley ebrey,1
+ali ibn yusuf,2
+caristii,1
+william l brandon,1
+fomite,5
+barcelona el prat airport,7
+mattequartier,4
+invading the sacred,1
+jefferson station,3
+chibalo,1
+phil voyles,1
+ramen,41
+archbishopric of athens,1
+robert arnot,1
+diethylhydroxylamine,2
+christian vazquez,1
+servage hosting,1
+ufo alien invasion,1
+blackburn railway station,3
+performance metric,19
+pencilings,1
+phosphoenolpyruvate,1
+under lights,2
+diego de la hoya,1
+felipe caicedo,5
+jimmy arguello,1
+cielo dalcamo,1
+jan navrátil,1
+linear pottery culture,9
+wbga,1
+k36dd,1
+die hard 2,22
+companding,8
+this is the modern world,10
+cosmology,26
+craig borten,1
+red pelicans,1
+ac gilbert,2
+fougasse,1
+leonardos robot,4
+john of whithorn,2
+david prescott barrows,2
+http cookie,168
+emilia telese,6
+herăstrău park,2
+lauro villar,1
+earl of lincoln,1
+born again,2
+milan rufus,1
+weper,2
+levitt bernstein,1
+jean de thevenot,1
+jill paton walsh,2
+leudal,1
+kyle mccafferty,1
+pluralistic walkthrough,2
+greetings to the new brunette,3
+angus maccoll,1
+loco live,2
+palm i705,1
+saila laakkonen,1
+ssta,1
+buch,1
+eduardo cunha,7
+marie bouliard,1
+mystic society,2
+chu jus house,1
+boob tube,8
+il mestiere della vita,1
+hadley fraser,7
+marek larwood,2
+imperial knight,2
+adbc,1
+houdini,8
+patrice talon,3
+iodamoeba,1
+long march,26
+nyinba,1
+maurice dunkley,1
+new south wales state election 1874–75,1
+john lee carroll,1
+poya bridge,1
+category talk military units and formations established in 2004,1
+the family values tour 1999,2
+brødrene hartmann,1
+miomelon,1
+john moran bailey,1
+san juan archipelago,1
+come as you are,7
+hypo niederösterreich,1
+saturn vi,2
+cherokee county kansas,1
+maher abu remeleh,1
+file talk jb grace singlejpg,1
+count paris,8
+template talk anime and manga,1
+kntv,4
+ganges river dolphin,4
+jerry pacht,1
+rapid response,1
+crunch bandicoot,1
+big gay love,2
+john mckay,1
+bareq,1
+nikon d2x,1
+intercontinental paris le grand hotel,1
+oakland alternative high school,1
+ekow eshun,1
+jimmy fortune,1
+american gladiator,2
+ella sophia armitage,1
+united we stand what more can i give,5
+maruti suzuki celerio,1
+geraldo rivera/trackback/,1
+dogs tobramycin contain a primary amine,1
+hot coffee mod,11
+shriners,25
+mora missouri,1
+seattle wa,1
+all star baseball 2003,1
+comparison of android e book reader software,7
+calling out loud,2
+initiative 912,1
+charles batchelor,2
+terry spraggan,2
+wallace thurman,2
+stefan smith,2
+george holding,22
+institute of business administration sukkar,1
+staten island new york,4
+valency,1
+chintamani taluk,1
+mahatma gandhi,1
+co orbital,1
+epex spot,1
+theodoric the great,3
+fk novi pazar,1
+zappas olympics,2
+gustav krupp von bohlen und halbach,1
+yasmany tomás,4
+notre temps,1
+cats %,1
+intramolecular vibrational energy redistribution,1
+graduate management admission test,49
+robin fleming,1
+daniel gadzhev,1
+achaean league,7
+the four books,1
+tunica people,1
+murray hurst,1
+hajipur,7
+wolfgang fischer,1
+bethel minnesota,2
+wincdemu,1
+aleksandar luković,5
+zilog,6
+will to live,1
+pgc,1
+captain sky,1
+eprobemide,1
+gunther plüschow,1
+jackson laboratory,3
+ss orontes,2
+bishop morlino,1
+eldorado air force station,2
+tin oxide,1
+john bell,2
+ajay banga,2
+nail polish remover induced contact dermatitis,1
+quinctia,1
+a/n urm 25d signal generator,1
+the art company,3
+seawind 300c,1
+half and half,7
+constantia czirenberg,1
+halifax county north carolina,4
+tunica vaginalis,9
+life & times of michael k,2
+methyl propionate,1
+carla bley band,1
+us secret service,2
+maría elena moyano,2
+lory meagher cup,9
+malay sultanate,1
+third lanark,1
+olivier dacourt,10
+angri,2
+ukrainian catholic eparchy of saints peter and paul,1
+phosphinooxazolines,1
+allied health professions,24
+hydroxybenzoic acid,1
+srinatha,3
+zone melting,5
+miko,1
+robert b downs,1
+resource management,3
+new year tree,1
+agraw imazighen,1
+catmando,8
+python ide,5
+rocky mount wilson roanoke rapids nc combined statistical area,1
+spanish crown,3
+ianis zicu,1
+william c hubbard,2
+islamic marital jurisprudence,5
+the school of night,1
+krdc,4
+el centro imperials,1
+atiq uz zaman,1
+sliba zkha,1
+file no mosquesvg,8
+herzegovinians,1
+paradise lost,1
+the fairly oddparents,6
+civic alliance,1
+anbu,3
+broadcaster,2
+le bon,1
+columbus nebraska,4
+inuit people,1
+the menace,6
+ilya ilyich mechnikov,1
+algonquin college,4
+seat córdoba wrc,1
+european route e30,6
+three lakes florida,1
+k10de,1
+glyphonyx rhopalacanthus,1
+ask rhod gilbert,1
+bolas criollas,1
+county borough of southport,1
+roll on mississippi,1
+pulitzer prize for photography,7
+mark fisher,1
+oakley g kelly,1
+tajikistani presidential election 1999,1
+the relapse,4
+nabil bentaleb,8
+apprentice,1
+dale brown,3
+studebaker packard hawk series,1
+yu gi oh trading card game,14
+paralimni,2
+institut national polytechnique de toulouse,1
+to catch a spy,1
+hammer,4
+mount judi,2
+thomas posey,1
+maxime baca,1
+arthur susskind,1
+elkins constructors,2
+siege of gaeta,1
+pemex,1
+henry o flipper award,1
+mccordsville indiana,1
+carife,1
+prima donna,1
+proton,1
+henry farrell,1
+randall davidson,1
+history of georgia,11
+beef tongue,4
+ted spread,4
+douglas xt 30,3
+heavenly mother,1
+monte santangelo,1
+lothar matthaus,1
+american party,2
+tire kingdom,1
+bastrop state park,3
+james maurice gavin,1
+blue bird all american,4
+time and a word,10
+runny babbit,1
+nordic regional airlines,6
+advanced scientifics,2
+the space traders,2
+mongol invasion of anatolia,1
+abu hayyan al gharnati,1
+lisa geoghan,3
+valentia harbour railway station,1
+silo,10
+jimmy zhingchak,1
+glamma kid,1
+bonneville high school,1
+secant line,5
+the longshots,2
+costa rican general election 1917,1
+an emotion away,1
+rawlins high school,1
+cold inflation pressure,4
+receptionthe,2
+tom payne,8
+tb treatment,1
+hatikvah,8
+ol yellow eyes is back,1
+vincent mroz,1
+travis bickle,1
+qatar stars league 1985–86,1
+electronic document management,1
+orliska,1
+gáspár orbán,1
+sunabeda,1
+donatus magnus,1
+lawrence e spivak,2
+cavalieri,1
+aw kuchler,1
+coat of arms of kuwait,1
+wallis–zieff–goldblatt syndrome,1
+doug heffernan,3
+g3 battlecruiser,3
+imran abbas,1
+plymouth,1
+gould colorado,1
+in japan,1
+delmar watson,1
+skygusty west virginia,1
+vesque sisters,1
+rushton triangular lodge,1
+italic font,3
+warner w hodgdon carolina 500,1
+blackamoors,5
+magna cum laude,14
+follow that horse,1
+jean snella,1
+chris frith,1
+soul power,2
+spare me the details,1
+ymer xhaferi,1
+murano glass,5
+michel magras,1
+rashard and wallace go to white castle,1
+venus figurines of malta,1
+didnt we almost have it all,1
+ew,1
+david h koch institute for integrative cancer research,2
+black coyote,1
+priob,2
+piera coppola,1
+budhism,4
+south african class h1 4 8 2t,1
+dimitris papamichael+dimitris+papamixail,3
+system sensor,1
+farragut class destroyer,1
+no down payment,1
+william rogers,1
+desperate choices to save my child,1
+joe launchbury,7
+queen seondeok of silla,11
+adams county wisconsin,1
+bandhan bank,1
+x ray tubes,1
+sporadic group,1
+lozovaya,1
+mairead maguire,3
+royal challengers bangalore in 2016,1
+janko of czarnków,1
+marosormenyes,1
+the deadly reclaim,1
+rick doblin,1
+gwen jorgensen,6
+shire of halls creek,1
+carlton house,6
+urad bean,1
+baton rouge louisiana,39
+kiel institute for the world economy,3
+the satuc cup,1
+harlem division,1
+argonaut,2
+choi jeongrye,2
+optical disc image,2
+groesbeek canadian war cemetery,2
+rangpur india,1
+android n,72
+tjeld class patrol boat,1
+together for yes,2
+tender dracula,1
+shane nelson,1
+palazzo ducale urbino,1
+angels,4
+double centralizer theorem,1
+homme,4
+world heart federation,1
+patricia ja lee,4
+a date with elvis,1
+saints row,1
+lanzhou lamian,1
+subcompact car,1
+jojo discography,5
+gary,18
+global returnable asset identifier,1
+aloysia weber,2
+emperor nero,2
+heavyweights,6
+hush records,1
+mewa textil service,2
+michigan gubernatorial election 1986,1
+solanine,9
+andré moritz,3
+foreign relations of china,12
+william t anderson,3
+lindquist field,1
+biggersdale hole,1
+manayunk/norristown line,1
+aliti,1
+budhivanta,3
+tm forum,4
+off plan property,1
+wu xin the monster killer,4
+aharon leib shteinman,1
+mark catano,1
+llanfihangel,1
+atp–adp translocase,4
+tótkomlós,1
+nikita magaloff,1
+xo telescope,1
+pseudomonas rhizosphaerae,1
+pccooler,1
+arcion therapeutics inc,8
+oklahoma gubernatorial election 2010,1
+seed treatment,3
+connecticut education network,1
+company85,1
+bryan molloy,1
+roupeiro,1
+wendt beach park,2
+entick v carrington,3
+firemens auxiliary,1
+shotcrete,14
+sepharial,1
+poet laureate of virginia,1
+musth,6
+dragon run state forest,3
+focal point,10
+pacific drilling,1
+intro,2
+priscus,1
+rokurō mochizuki,1
+bofur,2
+tiffany mount,1
+thanasis papazoglou,12
+life is grand,1
+ergersheim bas rhin,1
+medical reserve corps,3
+anthony ashley cooper 2nd earl of shaftesbury,1
+uefa euro 2012 group a,32
+america movil sab de cv,1
+christopher cook,1
+vladimir makanin,1
+file talk first battle of saratogausmaeduhistorygif,1
+dean foods,4
+logical thinking,1
+tychonic system,1
+hand washing,17
+bioresonance therapy,4
+günther burstyn,4
+religion in the united kingdom,35
+bancroft ontario,2
+alberta enterprise group,1
+belizean spanish,1
+minuscule 22,1
+hmga2,3
+sidama people,1
+shigeaki mori,2
+moonstars,1
+hazard,24
+chilis,6
+rango,3
+kenichi itō,1
+isle of rum,1
+shortwood united fc,1
+bronx gangs,1
+heterometaboly,2
+beagling,4
+jurgen pommerenke,1
+rockin,1
+st maria maggiore,1
+philipp reis,1
+timeboxing,12
+template talk tallahassee radio,1
+aarti puri,2
+john paul verree,2
+adam tomkins,1
+knoppers,1
+sven olov eriksson,1
+ruth bowyer,1
+höfðatorg tower 1,1
+citywire,3
+helen bosanquet,1
+ulex europaeus,4
+richard martyn,1
+hana sugisaki,2
+its all over now baby blue,6
+the myths and legends of king arthur and the knights of the round table,2
+dooce,1
+german submarine u 9,1
+george shearing,4
+bishop of winchester,3
+maximilian karl lamoral odonnell,2
+hec edmundson,1
+morgawr,3
+sovereign state,67
+avignon—la mitis—matane—matapédia,1
+duramax v8 engine,12
+villa rustica,2
+carl dorsey,1
+clairol,6
+abruzzo,22
+momsen lung,10
+m23 rebellion,2
+kira oreilly,1
+constitutive relation,2
+bifrontal craniotomy,1
+basilica of st nicholas amsterdam,2
+marinus kraus,1
+moog prodigy,2
+lucy hale,49
+lingiya,1
+idiopathic orbital inflammatory disease,3
+shaanxi youser group,1
+apeirohedron,1
+program of all inclusive care for the elderly,2
+tv3 ghana,3
+arnold schwarzenegger,338
+raquel carriedo tomás,1
+cincinnati playhouse in the park,2
+colobomata,2
+star craft 2,1
+yaaf,1
+fc santa clarita,1
+release me,3
+notts county supporters trust,1
+westchester airport,1
+slowhand at 70 – live at the royal albert hall,1
+bruce gray,2
+only the good die young,1
+sewell thomas stadium,1
+kyle cook,1
+northwest passage,1
+eurex airlines,1
+uss pierre,1
+feitsui dam,1
+sales force,1
+obrien class destroyer,5
+sant longowal institute of engineering and technology,3
+united states presidential election in oklahoma 1952,1
+edyta bartosiewicz,1
+marquess of dorset,1
+whiting wyoming,1
+akanda,1
+jim brewster,1
+mozdok republic of north ossetia alania,1
+maritime gendarmerie,2
+paresh patel,1
+communication art,1
+santa anita handicap,2
+dahlia,44
+qikpad,1
+pudhaiyal,3
+oroshi,1
+ioda,3
+willis j gertsch,1
+scurvy grass,1
+bombing of rotterdam,2
+gagarin russia,1
+dynamic apnea without fins,1
+loess,14
+hans adolf krebs,4
+poręby stare,1
+kismat ki baazi,1
+malcolm slesser,1
+blue crane route local municipality,1
+jean michel basquiat,104
+customs trade partnership against terrorism,3
+lower cove newfoundland and labrador,1
+aashiqui 2,6
+elliott lee,1
+edison electric light company,2
+i rigoberta menchú,1
+battle of tennōji,2
+transport workers union of america,1
+physical review b,1
+way too far,1
+breguet 941,1
+manuel hegen,1
+the blacklist,12
+john dorahy,4
+cinderella sanyu,1
+luis castañeda lossio,1
+headquarters of a military area,1
+jbala people,2
+petrofac emirates,1
+ins garuda,3
+australia national rugby league team,2
+state of emergency 2,3
+mexican sex comedy,2
+baby anikha,1
+notions,1
+android app //orgwikipedia/http/enmwikipediaorg/wiki/elasticity,1
+kissing you,2
+montearagón,1
+grzegorz proksa,3
+shook,1
+may hegglin anomaly,1
+chrysler rb engine,2
+gmcsf,2
+blacksburg,1
+chris hollod,1
+the new guy,1
+thulimbah queensland,1
+sust,1
+knight kadosh,2
+details,4
+nickel mining in new caledonia,3
+easter hotspot,1
+surinamese interior war,1
+field corn,2
+bolesław iii wrymouth,6
+lutwyche queensland,1
+michael campbell,1
+military ranks of turkey,3
+mícheal martin,1
+the architects dream,2
+joel robert,1
+thomas smith,1
+inclusion probability,1
+fucked company,1
+genderfluid,5
+lewisham by election 1891,1
+net promoter,98
+donald stewart,1
+xml base,2
+bhikhu parekh,4
+anthocharis cardamines,1
+vuosaari,1
+demographics of burundi,1
+dst,1
+david ensor,2
+mount pavlof,1
+vince young,5
+st beunos ignatian spirituality centre,4
+ezekiel 48,1
+lewis elliott chaze,1
+template talk croatia squad 2012 mens european water polo championship,1
+the voice of the philippines,4
+whites ferry,1
+cananga odorata,9
+man of steel,2
+john michael talbot,2
+superior oblique myokymia,2
+anisochilus,2
+e421,1
+midnight rider,14
+matrícula consular,1
+first nehru ministry,2
+christopher mcculloch,2
+ems chemie,12
+dominique martin,1
+university club of washington dc,1
+nurse education,5
+theyre coming to take me away ha haaa,1
+bill dauterive,4
+belhar,1
+heel and toe,4
+university of the arctic members,2
+mitava,1
+wjmx fm,1
+father callahan,4
+divine word academy of dagupan,1
+bogs,1
+denny heck,2
+church of st james valletta,1
+field cathedral of the polish army,1
+indian skimmer,1
+history of british airways,3
+international mobile subscriber identity,38
+suzel roche,1
+steven watt,1
+duke ellineton,1
+kirbys avalanche,4
diff --git a/tests/testdata/will_play_text.csv.bz2 b/tests/testdata/will_play_text.csv.bz2
new file mode 100755
index 0000000..e3bec9d
--- /dev/null
+++ b/tests/testdata/will_play_text.csv.bz2
Binary files differ
diff --git a/tox.ini b/tox.ini
index 7805296..7d79d38 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,7 +1,7 @@
[pytest]
addopts = -s
markers =
- json: run only the redisjson module tests
+ redismod: run only the redis module tests
[tox]
minversion = 3.2.0