ferret 0.10.13 → 0.10.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +5 -2
- data/ext/index.c +1 -1
- data/ext/q_phrase.c +6 -1
- data/ext/q_span.c +444 -6
- data/ext/r_search.c +95 -1
- data/ext/search.c +2 -1
- data/ext/search.h +32 -1
- data/ext/sort.c +1 -1
- data/lib/ferret/index.rb +2 -0
- data/lib/ferret_version.rb +1 -1
- data/test/unit/analysis/tc_analyzer.rb +13 -13
- data/test/unit/analysis/tc_token_stream.rb +5 -5
- data/test/unit/search/tc_spans.rb +19 -3
- data/test/unit/search/tm_searcher.rb +7 -1
- metadata +123 -123
data/Rakefile
CHANGED
@@ -41,7 +41,7 @@ SRC = (FileList["ext/*.[ch]"] + EXT_SRC_DEST).uniq
|
|
41
41
|
|
42
42
|
CLEAN.include(FileList['**/*.o', '**/*.obj', 'InstalledFiles',
|
43
43
|
'.config', 'ext/cferret.c'])
|
44
|
-
CLOBBER.include(FileList['**/*.so'], 'ext/Makefile',
|
44
|
+
CLOBBER.include(FileList['**/*.so'], 'ext/Makefile', EXT_SRC_DEST)
|
45
45
|
POLISH = Rake::FileList.new.include(FileList['**/*.so'], 'ext/Makefile')
|
46
46
|
|
47
47
|
desc "Clean specifically for the release."
|
@@ -115,7 +115,10 @@ EXT_SRC.each do |fn|
|
|
115
115
|
end if File.exists?("../c")
|
116
116
|
|
117
117
|
desc "Build the extension"
|
118
|
-
task :ext => ["ext/#{EXT}"] + SRC
|
118
|
+
task :ext => ["ext/#{EXT}"] + SRC do
|
119
|
+
rm_f 'ext/mem_pool.*'
|
120
|
+
rm_f 'ext/defines.h'
|
121
|
+
end
|
119
122
|
|
120
123
|
file "ext/#{EXT}" => ["ext/Makefile"] do
|
121
124
|
cp "ext/inc/lang.h", "ext/lang.h"
|
data/ext/index.c
CHANGED
@@ -91,7 +91,7 @@ HashTable *co_hash_create()
|
|
91
91
|
*
|
92
92
|
****************************************************************************/
|
93
93
|
|
94
|
-
|
94
|
+
__inline void fi_set_store(FieldInfo *fi, int store)
|
95
95
|
{
|
96
96
|
switch (store) {
|
97
97
|
case STORE_NO:
|
data/ext/q_phrase.c
CHANGED
@@ -898,7 +898,12 @@ static char *phq_to_s(Query *self, const char *field)
|
|
898
898
|
char *buffer;
|
899
899
|
|
900
900
|
if (phq->pos_cnt == 0) {
|
901
|
-
|
901
|
+
if (strcmp(field, phq->field) != 0) {
|
902
|
+
return strfmt("%s:\"\"", phq->field);
|
903
|
+
}
|
904
|
+
else {
|
905
|
+
return estrdup("\"\"");
|
906
|
+
}
|
902
907
|
}
|
903
908
|
|
904
909
|
/* sort the phrase positions by position */
|
data/ext/q_span.c
CHANGED
@@ -439,6 +439,208 @@ static SpanEnum *spante_new(Query *query, IndexReader *ir)
|
|
439
439
|
return self;
|
440
440
|
}
|
441
441
|
|
442
|
+
/*****************************************************************************
|
443
|
+
* SpanMultiTermEnum
|
444
|
+
*****************************************************************************/
|
445
|
+
|
446
|
+
/* * TermPosEnumWrapper * */
|
447
|
+
#define TPE_READ_SIZE 16
|
448
|
+
|
449
|
+
typedef struct TermPosEnumWrapper
|
450
|
+
{
|
451
|
+
const char *term;
|
452
|
+
TermDocEnum *tpe;
|
453
|
+
int doc;
|
454
|
+
int pos;
|
455
|
+
} TermPosEnumWrapper;
|
456
|
+
|
457
|
+
static bool tpew_less_than(const TermPosEnumWrapper *tpew1,
|
458
|
+
const TermPosEnumWrapper *tpew2)
|
459
|
+
{
|
460
|
+
return (tpew1->doc < tpew2->doc)
|
461
|
+
|| (tpew1->doc == tpew2->doc && tpew1->pos < tpew2->pos);
|
462
|
+
}
|
463
|
+
|
464
|
+
static bool tpew_next(TermPosEnumWrapper *self)
|
465
|
+
{
|
466
|
+
TermDocEnum *tpe = self->tpe;
|
467
|
+
if (0 > (self->pos = tpe->next_position(tpe))) {
|
468
|
+
if (!tpe->next(tpe)) return false;
|
469
|
+
self->doc = tpe->doc_num(tpe);
|
470
|
+
self->pos = tpe->next_position(tpe);
|
471
|
+
}
|
472
|
+
return true;
|
473
|
+
}
|
474
|
+
|
475
|
+
static bool tpew_skip_to(TermPosEnumWrapper *self, int doc_num)
|
476
|
+
{
|
477
|
+
TermDocEnum *tpe = self->tpe;
|
478
|
+
|
479
|
+
if (tpe->skip_to(tpe, doc_num)) {
|
480
|
+
self->doc = tpe->doc_num(tpe);
|
481
|
+
self->pos = tpe->next_position(tpe);
|
482
|
+
return true;
|
483
|
+
}
|
484
|
+
else {
|
485
|
+
return false;
|
486
|
+
}
|
487
|
+
}
|
488
|
+
|
489
|
+
static void tpew_destroy(TermPosEnumWrapper *self)
|
490
|
+
{
|
491
|
+
self->tpe->close(self->tpe);
|
492
|
+
free(self);
|
493
|
+
}
|
494
|
+
|
495
|
+
static TermPosEnumWrapper *tpew_new(const char *term, TermDocEnum *tpe)
|
496
|
+
{
|
497
|
+
TermPosEnumWrapper *self = ALLOC_AND_ZERO(TermPosEnumWrapper);
|
498
|
+
self->term = term;
|
499
|
+
self->tpe = tpe;
|
500
|
+
self->doc = -1;
|
501
|
+
self->pos = -1;
|
502
|
+
return self;
|
503
|
+
}
|
504
|
+
#define SpMTEn(span_enum) ((SpanMultiTermEnum *)(span_enum))
|
505
|
+
#define SpMTQ(query) ((SpanMultiTermQuery *)(query))
|
506
|
+
|
507
|
+
typedef struct SpanMultiTermEnum
|
508
|
+
{
|
509
|
+
SpanEnum super;
|
510
|
+
PriorityQueue *tpew_pq;
|
511
|
+
TermPosEnumWrapper **tpews;
|
512
|
+
int tpew_cnt;
|
513
|
+
int pos;
|
514
|
+
int doc;
|
515
|
+
} SpanMultiTermEnum;
|
516
|
+
|
517
|
+
static bool spanmte_next(SpanEnum *self)
|
518
|
+
{
|
519
|
+
int curr_doc, curr_pos;
|
520
|
+
TermPosEnumWrapper *tpew;
|
521
|
+
SpanMultiTermEnum *mte = SpMTEn(self);
|
522
|
+
PriorityQueue *tpew_pq = mte->tpew_pq;
|
523
|
+
if (tpew_pq == NULL) {
|
524
|
+
TermPosEnumWrapper **tpews = mte->tpews;
|
525
|
+
int i;
|
526
|
+
tpew_pq = pq_new(mte->tpew_cnt, (lt_ft)tpew_less_than, (free_ft)NULL);
|
527
|
+
for (i = mte->tpew_cnt - 1; i >= 0; i--) {
|
528
|
+
if (tpew_next(tpews[i])) {
|
529
|
+
pq_push(tpew_pq, tpews[i]);
|
530
|
+
}
|
531
|
+
}
|
532
|
+
mte->tpew_pq = tpew_pq;
|
533
|
+
}
|
534
|
+
|
535
|
+
tpew = (TermPosEnumWrapper *)pq_top(tpew_pq);
|
536
|
+
if (tpew == NULL) {
|
537
|
+
return false;
|
538
|
+
}
|
539
|
+
|
540
|
+
mte->doc = curr_doc = tpew->doc;
|
541
|
+
mte->pos = curr_pos = tpew->pos;
|
542
|
+
|
543
|
+
do {
|
544
|
+
if (tpew_next(tpew)) {
|
545
|
+
pq_down(tpew_pq);
|
546
|
+
}
|
547
|
+
else {
|
548
|
+
pq_pop(tpew_pq);
|
549
|
+
}
|
550
|
+
} while (((tpew = (TermPosEnumWrapper *)pq_top(tpew_pq)) != NULL)
|
551
|
+
&& tpew->doc == curr_doc && tpew->pos == curr_pos);
|
552
|
+
return true;
|
553
|
+
}
|
554
|
+
|
555
|
+
static bool spanmte_skip_to(SpanEnum *self, int target)
|
556
|
+
{
|
557
|
+
SpanMultiTermEnum *mte = SpMTEn(self);
|
558
|
+
PriorityQueue *tpew_pq = mte->tpew_pq;
|
559
|
+
TermPosEnumWrapper *tpew;
|
560
|
+
if (tpew_pq == NULL) {
|
561
|
+
TermPosEnumWrapper **tpews = mte->tpews;
|
562
|
+
int i;
|
563
|
+
tpew_pq = pq_new(mte->tpew_cnt, (lt_ft)tpew_less_than, (free_ft)NULL);
|
564
|
+
for (i = mte->tpew_cnt - 1; i >= 0; i--) {
|
565
|
+
tpew_skip_to(tpews[i], target);
|
566
|
+
pq_push(tpew_pq, tpews[i]);
|
567
|
+
}
|
568
|
+
mte->tpew_pq = tpew_pq;
|
569
|
+
}
|
570
|
+
if (tpew_pq->size == 0) {
|
571
|
+
mte->doc = -1;
|
572
|
+
return false;
|
573
|
+
}
|
574
|
+
while ((tpew = (TermPosEnumWrapper *)pq_top(tpew_pq)) != NULL
|
575
|
+
&& (target > tpew->doc)) {
|
576
|
+
if (tpew_skip_to(tpew, target)) {
|
577
|
+
pq_down(tpew_pq);
|
578
|
+
}
|
579
|
+
else {
|
580
|
+
pq_pop(tpew_pq);
|
581
|
+
}
|
582
|
+
}
|
583
|
+
return spanmte_next(self);
|
584
|
+
}
|
585
|
+
|
586
|
+
static int spanmte_doc(SpanEnum *self)
|
587
|
+
{
|
588
|
+
return SpMTEn(self)->doc;
|
589
|
+
}
|
590
|
+
|
591
|
+
static int spanmte_start(SpanEnum *self)
|
592
|
+
{
|
593
|
+
return SpMTEn(self)->pos;
|
594
|
+
}
|
595
|
+
|
596
|
+
static int spanmte_end(SpanEnum *self)
|
597
|
+
{
|
598
|
+
return SpMTEn(self)->pos + 1;
|
599
|
+
}
|
600
|
+
|
601
|
+
static void spanmte_destroy(SpanEnum *self)
|
602
|
+
{
|
603
|
+
SpanMultiTermEnum *mte = SpMTEn(self);
|
604
|
+
int i;
|
605
|
+
if (mte->tpew_pq) pq_destroy(mte->tpew_pq);
|
606
|
+
for (i = 0; i < mte->tpew_cnt; i++) {
|
607
|
+
tpew_destroy(mte->tpews[i]);
|
608
|
+
}
|
609
|
+
free(mte->tpews);
|
610
|
+
free(self);
|
611
|
+
}
|
612
|
+
|
613
|
+
static SpanEnum *spanmte_new(Query *query, IndexReader *ir)
|
614
|
+
{
|
615
|
+
char *field = SpQ(query)->field;
|
616
|
+
SpanEnum *self = (SpanEnum *)emalloc(sizeof(SpanMultiTermEnum));
|
617
|
+
SpanMultiTermEnum *smte = SpMTEn(self);
|
618
|
+
SpanMultiTermQuery *smtq = SpMTQ(query);
|
619
|
+
int i;
|
620
|
+
|
621
|
+
|
622
|
+
smte->tpews = ALLOC_N(TermPosEnumWrapper *, smtq->term_cnt);
|
623
|
+
for (i = 0; i < smtq->term_cnt; i++) {
|
624
|
+
char *term = smtq->terms[i];
|
625
|
+
smte->tpews[i] = tpew_new(term, ir_term_positions_for(ir, field, term));
|
626
|
+
}
|
627
|
+
smte->tpew_cnt = smtq->term_cnt;
|
628
|
+
smte->tpew_pq = NULL;
|
629
|
+
smte->pos = -1;
|
630
|
+
smte->doc = -1;
|
631
|
+
|
632
|
+
self->query = query;
|
633
|
+
self->next = &spanmte_next;
|
634
|
+
self->skip_to = &spanmte_skip_to;
|
635
|
+
self->doc = &spanmte_doc;
|
636
|
+
self->start = &spanmte_start;
|
637
|
+
self->end = &spanmte_end;
|
638
|
+
self->destroy = &spanmte_destroy;
|
639
|
+
self->to_s = &spante_to_s;
|
640
|
+
|
641
|
+
return self;
|
642
|
+
}
|
643
|
+
|
442
644
|
|
443
645
|
/*****************************************************************************
|
444
646
|
* SpanFirstEnum
|
@@ -1385,6 +1587,132 @@ Query *spantq_new(const char *field, const char *term)
|
|
1385
1587
|
return self;
|
1386
1588
|
}
|
1387
1589
|
|
1590
|
+
/*****************************************************************************
|
1591
|
+
* SpanMultiTermQuery
|
1592
|
+
*****************************************************************************/
|
1593
|
+
|
1594
|
+
static char *spanmtq_to_s(Query *self, const char *field)
|
1595
|
+
{
|
1596
|
+
char *terms = NULL, *p;
|
1597
|
+
int len = 2, i;
|
1598
|
+
SpanMultiTermQuery *smtq = SpMTQ(self);
|
1599
|
+
for (i = 0; i < smtq->term_cnt; i++) {
|
1600
|
+
len += strlen(smtq->terms[i]) + 2;
|
1601
|
+
}
|
1602
|
+
p = terms = ALLOC_N(char, len);
|
1603
|
+
*(p++) = '[';
|
1604
|
+
for (i = 0; i < smtq->term_cnt; i++) {
|
1605
|
+
strcpy(p, smtq->terms[i]);
|
1606
|
+
p += strlen(smtq->terms[i]);
|
1607
|
+
*(p++) = ',';
|
1608
|
+
}
|
1609
|
+
if (p > terms) p--;
|
1610
|
+
*(p++) = ']';
|
1611
|
+
*p = '\0';
|
1612
|
+
|
1613
|
+
if (field == SpQ(self)->field) {
|
1614
|
+
p = strfmt("span_terms(%s)", terms);
|
1615
|
+
}
|
1616
|
+
else {
|
1617
|
+
p = strfmt("span_terms(%s:%s)", SpQ(self)->field, terms);
|
1618
|
+
}
|
1619
|
+
free(terms);
|
1620
|
+
return p;
|
1621
|
+
}
|
1622
|
+
|
1623
|
+
static void spanmtq_destroy_i(Query *self)
|
1624
|
+
{
|
1625
|
+
SpanMultiTermQuery *smtq = SpMTQ(self);
|
1626
|
+
int i;
|
1627
|
+
for (i = 0; i < smtq->term_cnt; i++) {
|
1628
|
+
free(smtq->terms[i]);
|
1629
|
+
}
|
1630
|
+
free(smtq->terms);
|
1631
|
+
free(SpQ(self)->field);
|
1632
|
+
spanq_destroy_i(self);
|
1633
|
+
}
|
1634
|
+
|
1635
|
+
static void spanmtq_extract_terms(Query *self, HashSet *terms)
|
1636
|
+
{
|
1637
|
+
SpanMultiTermQuery *smtq = SpMTQ(self);
|
1638
|
+
int i;
|
1639
|
+
for (i = 0; i < smtq->term_cnt; i++) {
|
1640
|
+
hs_add(terms, term_new(SpQ(self)->field, smtq->terms[i]));
|
1641
|
+
}
|
1642
|
+
}
|
1643
|
+
|
1644
|
+
static HashSet *spanmtq_get_terms(Query *self)
|
1645
|
+
{
|
1646
|
+
HashSet *terms = hs_new_str(&free);
|
1647
|
+
SpanMultiTermQuery *smtq = SpMTQ(self);
|
1648
|
+
int i;
|
1649
|
+
for (i = 0; i < smtq->term_cnt; i++) {
|
1650
|
+
hs_add(terms, estrdup(smtq->terms[i]));
|
1651
|
+
}
|
1652
|
+
return terms;
|
1653
|
+
}
|
1654
|
+
|
1655
|
+
static unsigned long spanmtq_hash(Query *self)
|
1656
|
+
{
|
1657
|
+
unsigned long hash = spanq_hash(self);
|
1658
|
+
SpanMultiTermQuery *smtq = SpMTQ(self);
|
1659
|
+
int i;
|
1660
|
+
for (i = 0; i < smtq->term_cnt; i++) {
|
1661
|
+
hash ^= str_hash(smtq->terms[i]);
|
1662
|
+
}
|
1663
|
+
return hash;
|
1664
|
+
}
|
1665
|
+
|
1666
|
+
static int spanmtq_eq(Query *self, Query *o)
|
1667
|
+
{
|
1668
|
+
SpanMultiTermQuery *smtq = SpMTQ(self);
|
1669
|
+
SpanMultiTermQuery *smtqo = SpMTQ(o);
|
1670
|
+
int i;
|
1671
|
+
if (!spanq_eq(self, o)) return false;
|
1672
|
+
if (smtq->term_cnt != smtqo->term_cnt) return false;
|
1673
|
+
for (i = 0; i < smtq->term_cnt; i++) {
|
1674
|
+
if (strcmp(smtq->terms[i], smtqo->terms[i]) != 0) return false;
|
1675
|
+
}
|
1676
|
+
return true;;
|
1677
|
+
}
|
1678
|
+
|
1679
|
+
Query *spanmtq_new_conf(const char *field, int max_terms)
|
1680
|
+
{
|
1681
|
+
Query *self = q_new(SpanMultiTermQuery);
|
1682
|
+
|
1683
|
+
SpMTQ(self)->terms = ALLOC_N(char *, max_terms);
|
1684
|
+
SpMTQ(self)->term_cnt = 0;
|
1685
|
+
SpMTQ(self)->term_capa = max_terms;
|
1686
|
+
|
1687
|
+
SpQ(self)->field = estrdup(field);
|
1688
|
+
SpQ(self)->get_spans = &spanmte_new;
|
1689
|
+
SpQ(self)->get_terms = &spanmtq_get_terms;
|
1690
|
+
|
1691
|
+
self->type = SPAN_MULTI_TERM_QUERY;
|
1692
|
+
self->extract_terms = &spanmtq_extract_terms;
|
1693
|
+
self->to_s = &spanmtq_to_s;
|
1694
|
+
self->hash = &spanmtq_hash;
|
1695
|
+
self->eq = &spanmtq_eq;
|
1696
|
+
self->destroy_i = &spanmtq_destroy_i;
|
1697
|
+
self->create_weight_i = &spanw_new;
|
1698
|
+
self->get_matchv_i = &spanq_get_matchv_i;
|
1699
|
+
|
1700
|
+
return self;
|
1701
|
+
}
|
1702
|
+
|
1703
|
+
Query *spanmtq_new(const char *field)
|
1704
|
+
{
|
1705
|
+
return spanmtq_new_conf(field, SPAN_MULTI_TERM_QUERY_CAPA);
|
1706
|
+
}
|
1707
|
+
|
1708
|
+
void spanmtq_add_term(Query *self, const char *term)
|
1709
|
+
{
|
1710
|
+
SpanMultiTermQuery *smtq = SpMTQ(self);
|
1711
|
+
if (smtq->term_cnt < smtq->term_capa) {
|
1712
|
+
smtq->terms[smtq->term_cnt++] = estrdup(term);
|
1713
|
+
}
|
1714
|
+
}
|
1715
|
+
|
1388
1716
|
/*****************************************************************************
|
1389
1717
|
*
|
1390
1718
|
* SpanFirstQuery
|
@@ -1427,6 +1755,7 @@ static Query *spanfq_rewrite(Query *self, IndexReader *ir)
|
|
1427
1755
|
static void spanfq_destroy_i(Query *self)
|
1428
1756
|
{
|
1429
1757
|
q_deref(SpFQ(self)->match);
|
1758
|
+
free(SpQ(self)->field);
|
1430
1759
|
spanq_destroy_i(self);
|
1431
1760
|
}
|
1432
1761
|
|
@@ -1451,7 +1780,7 @@ Query *spanfq_new_nr(Query *match, int end)
|
|
1451
1780
|
SpFQ(self)->match = match;
|
1452
1781
|
SpFQ(self)->end = end;
|
1453
1782
|
|
1454
|
-
SpQ(self)->field = SpQ(match)->field;
|
1783
|
+
SpQ(self)->field = estrdup(SpQ(match)->field);
|
1455
1784
|
SpQ(self)->get_spans = &spanfe_new;
|
1456
1785
|
SpQ(self)->get_terms = &spanfq_get_terms;
|
1457
1786
|
|
@@ -1569,6 +1898,7 @@ static void spanoq_destroy_i(Query *self)
|
|
1569
1898
|
q_deref(clause);
|
1570
1899
|
}
|
1571
1900
|
free(soq->clauses);
|
1901
|
+
free(SpQ(self)->field);
|
1572
1902
|
|
1573
1903
|
spanq_destroy_i(self);
|
1574
1904
|
}
|
@@ -1612,7 +1942,7 @@ Query *spanoq_new()
|
|
1612
1942
|
SpOQ(self)->clauses = ALLOC_N(Query *, CLAUSE_INIT_CAPA);
|
1613
1943
|
SpOQ(self)->c_capa = CLAUSE_INIT_CAPA;
|
1614
1944
|
|
1615
|
-
SpQ(self)->field = (char *)EMPTY_STRING;
|
1945
|
+
SpQ(self)->field = estrdup((char *)EMPTY_STRING);
|
1616
1946
|
SpQ(self)->get_spans = &spanoq_get_spans;
|
1617
1947
|
SpQ(self)->get_terms = &spanoq_get_terms;
|
1618
1948
|
|
@@ -1637,7 +1967,8 @@ Query *spanoq_add_clause_nr(Query *self, Query *clause)
|
|
1637
1967
|
"SpanQuery.", q_get_query_name(clause->type));
|
1638
1968
|
}
|
1639
1969
|
if (curr_index == 0) {
|
1640
|
-
SpQ(self)->field
|
1970
|
+
free(SpQ(self)->field);
|
1971
|
+
SpQ(self)->field = estrdup(SpQ(clause)->field);
|
1641
1972
|
}
|
1642
1973
|
else if (strcmp(SpQ(self)->field, SpQ(clause)->field) != 0) {
|
1643
1974
|
RAISE(ARG_ERROR, "All clauses in a SpanQuery must have the same field. "
|
@@ -1752,6 +2083,7 @@ static void spannq_destroy(Query *self)
|
|
1752
2083
|
q_deref(clause);
|
1753
2084
|
}
|
1754
2085
|
free(snq->clauses);
|
2086
|
+
free(SpQ(self)->field);
|
1755
2087
|
|
1756
2088
|
spanq_destroy_i(self);
|
1757
2089
|
}
|
@@ -1804,7 +2136,7 @@ Query *spannq_new(int slop, bool in_order)
|
|
1804
2136
|
|
1805
2137
|
SpQ(self)->get_spans = &spannq_get_spans;
|
1806
2138
|
SpQ(self)->get_terms = &spannq_get_terms;
|
1807
|
-
SpQ(self)->field = (char *)EMPTY_STRING;
|
2139
|
+
SpQ(self)->field = estrdup((char *)EMPTY_STRING);
|
1808
2140
|
|
1809
2141
|
self->type = SPAN_NEAR_QUERY;
|
1810
2142
|
self->rewrite = &spannq_rewrite;
|
@@ -1827,7 +2159,8 @@ Query *spannq_add_clause_nr(Query *self, Query *clause)
|
|
1827
2159
|
"SpanQuery.", q_get_query_name(clause->type));
|
1828
2160
|
}
|
1829
2161
|
if (curr_index == 0) {
|
1830
|
-
SpQ(self)->field
|
2162
|
+
free(SpQ(self)->field);
|
2163
|
+
SpQ(self)->field = estrdup(SpQ(clause)->field);
|
1831
2164
|
}
|
1832
2165
|
else if (strcmp(SpQ(self)->field, SpQ(clause)->field) != 0) {
|
1833
2166
|
RAISE(ARG_ERROR, "All clauses in a SpanQuery must have the same field. "
|
@@ -1904,6 +2237,8 @@ static void spanxq_destroy(Query *self)
|
|
1904
2237
|
q_deref(sxq->inc);
|
1905
2238
|
q_deref(sxq->exc);
|
1906
2239
|
|
2240
|
+
free(SpQ(self)->field);
|
2241
|
+
|
1907
2242
|
spanq_destroy_i(self);
|
1908
2243
|
}
|
1909
2244
|
|
@@ -1937,7 +2272,7 @@ Query *spanxq_new_nr(Query *inc, Query *exc)
|
|
1937
2272
|
SpXQ(self)->inc = inc;
|
1938
2273
|
SpXQ(self)->exc = exc;
|
1939
2274
|
|
1940
|
-
SpQ(self)->field = SpQ(inc)->field;
|
2275
|
+
SpQ(self)->field = estrdup(SpQ(inc)->field);
|
1941
2276
|
SpQ(self)->get_spans = &spanxe_new;
|
1942
2277
|
SpQ(self)->get_terms = &spanxq_get_terms;
|
1943
2278
|
|
@@ -1961,3 +2296,106 @@ Query *spanxq_new(Query *inc, Query *exc)
|
|
1961
2296
|
return spanxq_new_nr(inc, exc);
|
1962
2297
|
}
|
1963
2298
|
|
2299
|
+
|
2300
|
+
/*****************************************************************************
|
2301
|
+
*
|
2302
|
+
* Rewritables
|
2303
|
+
*
|
2304
|
+
*****************************************************************************/
|
2305
|
+
|
2306
|
+
/*****************************************************************************
|
2307
|
+
*
|
2308
|
+
* SpanPrefixQuery
|
2309
|
+
*
|
2310
|
+
*****************************************************************************/
|
2311
|
+
|
2312
|
+
#define SpPfxQ(query) ((SpanPrefixQuery *)(query))
|
2313
|
+
|
2314
|
+
static char *spanprq_to_s(Query *self, const char *current_field)
|
2315
|
+
{
|
2316
|
+
char *buffer, *bptr;
|
2317
|
+
const char *prefix = SpPfxQ(self)->prefix;
|
2318
|
+
const char *field = SpQ(self)->field;
|
2319
|
+
size_t plen = strlen(prefix);
|
2320
|
+
size_t flen = strlen(field);
|
2321
|
+
|
2322
|
+
bptr = buffer = ALLOC_N(char, plen + flen + 35);
|
2323
|
+
|
2324
|
+
if (strcmp(field, current_field) != 0) {
|
2325
|
+
sprintf(bptr, "%s:", field);
|
2326
|
+
bptr += flen + 1;
|
2327
|
+
}
|
2328
|
+
|
2329
|
+
sprintf(bptr, "%s*", prefix);
|
2330
|
+
bptr += plen + 1;
|
2331
|
+
if (self->boost != 1.0) {
|
2332
|
+
*bptr = '^';
|
2333
|
+
dbl_to_s(++bptr, self->boost);
|
2334
|
+
}
|
2335
|
+
|
2336
|
+
return buffer;
|
2337
|
+
}
|
2338
|
+
|
2339
|
+
static Query *spanprq_rewrite(Query *self, IndexReader *ir)
|
2340
|
+
{
|
2341
|
+
const char *field = SpQ(self)->field;
|
2342
|
+
const int field_num = fis_get_field_num(ir->fis, field);
|
2343
|
+
Query *volatile q = spanmtq_new_conf(field, SPAN_PREFIX_QUERY_MAX_TERMS);
|
2344
|
+
q->boost = self->boost; /* set the boost */
|
2345
|
+
|
2346
|
+
if (field_num >= 0) {
|
2347
|
+
const char *prefix = SpPfxQ(self)->prefix;
|
2348
|
+
TermEnum *te = ir->terms_from(ir, field_num, prefix);
|
2349
|
+
const char *term = te->curr_term;
|
2350
|
+
size_t prefix_len = strlen(prefix);
|
2351
|
+
|
2352
|
+
TRY
|
2353
|
+
do {
|
2354
|
+
if (strncmp(term, prefix, prefix_len) != 0) {
|
2355
|
+
break;
|
2356
|
+
}
|
2357
|
+
spanmtq_add_term(q, term); /* found a match */
|
2358
|
+
} while (te->next(te));
|
2359
|
+
XFINALLY
|
2360
|
+
te->close(te);
|
2361
|
+
XENDTRY
|
2362
|
+
}
|
2363
|
+
|
2364
|
+
return q;
|
2365
|
+
}
|
2366
|
+
|
2367
|
+
static void spanprq_destroy(Query *self)
|
2368
|
+
{
|
2369
|
+
free(SpQ(self)->field);
|
2370
|
+
free(SpPfxQ(self)->prefix);
|
2371
|
+
spanq_destroy_i(self);
|
2372
|
+
}
|
2373
|
+
|
2374
|
+
static unsigned long spanprq_hash(Query *self)
|
2375
|
+
{
|
2376
|
+
return str_hash(SpQ(self)->field) ^ str_hash(SpPfxQ(self)->prefix);
|
2377
|
+
}
|
2378
|
+
|
2379
|
+
static int spanprq_eq(Query *self, Query *o)
|
2380
|
+
{
|
2381
|
+
return (strcmp(SpPfxQ(self)->prefix, SpPfxQ(o)->prefix) == 0)
|
2382
|
+
&& (strcmp(SpQ(self)->field, SpQ(o)->field) == 0);
|
2383
|
+
}
|
2384
|
+
|
2385
|
+
Query *spanprq_new(const char *field, const char *prefix)
|
2386
|
+
{
|
2387
|
+
Query *self = q_new(SpanPrefixQuery);
|
2388
|
+
|
2389
|
+
SpQ(self)->field = estrdup(field);
|
2390
|
+
SpPfxQ(self)->prefix = estrdup(prefix);
|
2391
|
+
|
2392
|
+
self->type = SPAN_PREFIX_QUERY;
|
2393
|
+
self->rewrite = &spanprq_rewrite;
|
2394
|
+
self->to_s = &spanprq_to_s;
|
2395
|
+
self->hash = &spanprq_hash;
|
2396
|
+
self->eq = &spanprq_eq;
|
2397
|
+
self->destroy_i = &spanprq_destroy;
|
2398
|
+
self->create_weight_i = &q_create_weight_unsup;
|
2399
|
+
|
2400
|
+
return self;
|
2401
|
+
}
|