verify_corpus.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. """Acceptance checks against this actual, frozen Wang Yong collection."""
  2. import argparse
  3. import json
  4. import statistics
  5. import time
  6. from pathlib import Path
  7. import voc_db as v
  8. def verify(db):
  9. before = v.sha(Path(db).read_bytes())
  10. with v.readonly(db) as c:
  11. counts = v.table_counts(c)
  12. assert {k:counts[k] for k in ('products','reviews','social_posts','policy_documents','policy_clauses')} == dict(products=4639,reviews=2360,social_posts=3814,policy_documents=25,policy_clauses=31)
  13. assert c.execute('PRAGMA integrity_check').fetchone()[0] == 'ok'
  14. assert not c.execute('PRAGMA foreign_key_check').fetchall()
  15. assert c.execute("SELECT count(*) FROM products WHERE coverage_type='recovered_review_reference_partial_catalog'").fetchone()[0] == 4
  16. assert c.execute("SELECT count(*) FROM reviews WHERE product_id IS NULL").fetchone()[0] == 0
  17. assert c.execute("SELECT count(*) FROM source_links WHERE resolution!='matched'").fetchone()[0] == 0
  18. assert c.execute("SELECT count(*) FROM policy_documents WHERE attachment_hash_state='matched'").fetchone()[0] == 25
  19. assert c.execute('SELECT sum(is_default=0),sum(is_default=1) FROM reviews').fetchone()[:] == (789,1571)
  20. examples, timings = [], []
  21. for market in ('jd','tmall'):
  22. for entity in ('products','reviews','prices'):
  23. request = dict(entity=entity,marketplace=market,brand='ksf',category='banmian',limit=20)
  24. result = v.query(c,request,True)
  25. assert result['scopeCombination']=='AND'
  26. assert any('idx_products_scope' in p for p in result['queryPlan'])
  27. if entity=='reviews':assert any('idx_reviews_product' in p for p in result['queryPlan'])
  28. if entity=='prices':assert any('idx_prices_product_time' in p for p in result['queryPlan'])
  29. cursor, seen = None, set()
  30. while True:
  31. page = v.query(c,{**request, **({'cursor':cursor} if cursor else {})})
  32. for row in page['records']:
  33. assert (row['marketplace'],row['brand_code'],row['category_code']) == (market,'ksf','banmian')
  34. assert row['id'] not in seen
  35. assert row['citation']['archiveSha256']
  36. seen.add(row['id'])
  37. if entity=='reviews':
  38. assert row['is_default']==0 and row['identity_state']=='matched' and row['category_state']=='consistent'
  39. assert row['product_id'].startswith('jd:' if market=='jd' else 'taobao:')
  40. cursor=page['nextCursor']
  41. if cursor is None:break
  42. assert len(seen)==result['totalMatched']
  43. for _ in range(8):
  44. started=time.perf_counter();v.query(c,request);timings.append((time.perf_counter()-started)*1000)
  45. examples.append({'filters':request,'totalMatched':result['totalMatched'],'queryPlan':result['queryPlan'],'paginationComplete':True})
  46. # All registered brands remain isolated at the SQL layer.
  47. for market in ('jd','tmall'):
  48. for brand in c.execute('SELECT code FROM brands'):
  49. result=v.query(c,dict(entity='products',marketplace=market,brand=brand[0],category='banmian',limit=100))
  50. assert all(r['marketplace']==market and r['brand_code']==brand[0] and r['category_code']=='banmian' for r in result['records'])
  51. stats={
  52. 'classification':dict(c.execute('SELECT classification_state,count(*) FROM products GROUP BY 1')),
  53. 'marketplaces':[dict(r) for r in c.execute('SELECT marketplace,count(*) AS count FROM products GROUP BY 1')],
  54. 'reviews':[dict(r) for r in c.execute('SELECT marketplace_claim,identity_state,category_state,is_default,count(*) AS count FROM reviews GROUP BY 1,2,3,4')],
  55. 'quality':dict(c.execute('SELECT code,count(*) FROM quality_issues GROUP BY code')),
  56. 'validNumericPrices':c.execute('SELECT count(*) FROM prices WHERE amount_minor IS NOT NULL').fetchone()[0],
  57. 'verifiedUnitPrices':c.execute("SELECT count(*) FROM prices WHERE unit_price_verification='verified'").fetchone()[0],
  58. 'titleSpecCandidates':c.execute("SELECT count(*) FROM specs WHERE verification='title_candidate'").fetchone()[0],
  59. 'socialWithoutFulltext':c.execute('SELECT count(*) FROM social_posts WHERE fulltext_available=0').fetchone()[0]
  60. }
  61. generation=c.execute("SELECT value FROM meta WHERE key='generation'").fetchone()[0]
  62. assert before==v.sha(Path(db).read_bytes())
  63. return dict(ok=True,schema=v.VERSION,generation=generation,databaseSha256=before,counts=counts,statistics=stats,examples=examples,
  64. queryBenchmark=dict(samples=len(timings),medianMs=round(statistics.median(timings),3),maxMs=round(max(timings),3),scope='本机已有连接,查询20条并附来源;不含生产网络/Agent启动耗时'),
  65. checks=['integrity','foreign_keys','primary_counts','4_recovered_references','no_orphan_reviews','all_source_paths_matched','25_policy_hashes_with_explicit_basis','default_review_counts','exact_scope','review_sku_identity','all_brand_isolation','complete_keyset_pagination','compound_indexes','readonly_hash_unchanged'],
  66. productionDatabaseChanged=False,agentInstalled=False,publicBoardConnected=False)
  67. if __name__=='__main__':
  68. p=argparse.ArgumentParser();p.add_argument('--db',required=True);p.add_argument('--out',required=True);a=p.parse_args()
  69. result=verify(a.db)
  70. Path(a.out).write_text(json.dumps(result,ensure_ascii=False,indent=2)+'\n',encoding='utf-8')
  71. print(json.dumps({k:val for k,val in result.items() if k not in ('examples','statistics')},ensure_ascii=False,indent=2))