Elasticsearch "get by index" returns 文档,而 "match_all" returns 没有结果
Elasticsearch "get by index" returns the document, while "match_all" returns no results
我正在尝试模拟 elasticsearch 数据以用于托管 CI 单元测试目的。
我已经准备了一些可以用 bulk()
成功加载的固定装置,但是,由于未知原因,我无法匹配 任何东西,即使 test_index
似乎包含数据(因为我可以通过 ID get()
项目)。
fixtures.json
是我从实际生产索引中获取的 ES 文档的子集。使用真实世界的索引,一切都按预期工作并且所有测试都通过了。
奇怪行为的人工示例如下:
class MyTestCase(TestCase):
es = Elasticsearch()
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.es.indices.create('test_index', SOME_SCHEMA)
with open('fixtures.json') as fixtures:
bulk(cls.es, json.load(fixtures))
@classmethod
def tearDownClass(cls):
super().tearDownClass()
cls.es.indices.delete('test_index')
def test_something(self):
# check all documents are there:
with open('fixtures.json') as fixtures:
for f in json.load(fixtures):
print(self.es.get(index='test_index', id=f['_id']))
# yes they are!
# BUT:
match_all = {"query": {"match_all": {}}}
print('hits:', self.es.search(index='test_index', body=match_all)['hits']['hits'])
# prints `hits: []` like there was nothing in
print('count:', self.es.count(index='test_index', body=match_all)['count'])
# prints `count: 0`
虽然我完全理解您的痛苦(除了测试之外一切正常),但答案实际上很简单:与您的实验相比,测试太快了。
- Elasticsearch 是 near real-time 搜索引擎,这意味着
在索引文档和它被索引之间最多有 1 秒的延迟
可搜索。
- 还有不可预测的延迟(取决于实际
开销)在创建索引和准备就绪之间。
所以解决方法是 time.sleep()
给 ES 一些 space 来创造它需要给你结果的所有魔法。我会这样做:
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.es.indices.create('test_index', SOME_SCHEMA)
with open('fixtures.json') as fixtures:
bulk(cls.es, json.load(fixtures))
cls.wait_until_index_ready()
@classmethod
def wait_until_index_ready(cls, timeout=10):
for sec in range(timeout):
time.sleep(1)
if cls.es.cluster.health().get('status') in ('green', 'yellow'):
break
虽然@jsmesami 的回答非常正确,但有一种可能更简洁的方法可以做到这一点。如果您注意到,问题是因为 ES 没有重新编制索引。 API 实际上为此目的公开了一些函数。
尝试类似的东西,
cls.es.indices.flush(wait_if_ongoing=True)
cls.es.indices.refresh(index='*')
更具体地说,您可以将 index='test_index'
传递给这两个函数。我认为这是一种比使用 sleep(..)
.
更简洁、更具体的方法
我正在尝试模拟 elasticsearch 数据以用于托管 CI 单元测试目的。
我已经准备了一些可以用 bulk()
成功加载的固定装置,但是,由于未知原因,我无法匹配 任何东西,即使 test_index
似乎包含数据(因为我可以通过 ID get()
项目)。
fixtures.json
是我从实际生产索引中获取的 ES 文档的子集。使用真实世界的索引,一切都按预期工作并且所有测试都通过了。
奇怪行为的人工示例如下:
class MyTestCase(TestCase):
es = Elasticsearch()
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.es.indices.create('test_index', SOME_SCHEMA)
with open('fixtures.json') as fixtures:
bulk(cls.es, json.load(fixtures))
@classmethod
def tearDownClass(cls):
super().tearDownClass()
cls.es.indices.delete('test_index')
def test_something(self):
# check all documents are there:
with open('fixtures.json') as fixtures:
for f in json.load(fixtures):
print(self.es.get(index='test_index', id=f['_id']))
# yes they are!
# BUT:
match_all = {"query": {"match_all": {}}}
print('hits:', self.es.search(index='test_index', body=match_all)['hits']['hits'])
# prints `hits: []` like there was nothing in
print('count:', self.es.count(index='test_index', body=match_all)['count'])
# prints `count: 0`
虽然我完全理解您的痛苦(除了测试之外一切正常),但答案实际上很简单:与您的实验相比,测试太快了。
- Elasticsearch 是 near real-time 搜索引擎,这意味着 在索引文档和它被索引之间最多有 1 秒的延迟 可搜索。
- 还有不可预测的延迟(取决于实际 开销)在创建索引和准备就绪之间。
所以解决方法是 time.sleep()
给 ES 一些 space 来创造它需要给你结果的所有魔法。我会这样做:
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.es.indices.create('test_index', SOME_SCHEMA)
with open('fixtures.json') as fixtures:
bulk(cls.es, json.load(fixtures))
cls.wait_until_index_ready()
@classmethod
def wait_until_index_ready(cls, timeout=10):
for sec in range(timeout):
time.sleep(1)
if cls.es.cluster.health().get('status') in ('green', 'yellow'):
break
虽然@jsmesami 的回答非常正确,但有一种可能更简洁的方法可以做到这一点。如果您注意到,问题是因为 ES 没有重新编制索引。 API 实际上为此目的公开了一些函数。 尝试类似的东西,
cls.es.indices.flush(wait_if_ongoing=True)
cls.es.indices.refresh(index='*')
更具体地说,您可以将 index='test_index'
传递给这两个函数。我认为这是一种比使用 sleep(..)
.