[Glass] There is really no way to have an ordered/sorted collection together with indexes?

Dale Henrichs via Glass glass at lists.gemtalksystems.com
Mon Aug 7 19:06:57 PDT 2017


Here's an updated script to show how to use a query with two different 
dates ... targetDate1 is a random date presumed to miss any existing 
data ... targetDate2 is a date from a known sample ......


       | nsc random maxYear detectQuery targetDate1 targetDate2 result1 
result2 nearestQuery theDate |
       nsc := IdentityBag new.
       random := HostRandom new.
       GsIndexSpec new
         equalityIndex: 'value' lastElementClass: Date;
         createIndexesOn: nsc.
       detectQuery := GsQuery fromString: 'each.value = targetDate' on: nsc.
       nearestQuery :=  GsQuery fromString: 'each.value < targetDate' 
on: nsc.
       1 to: 100 do: [ :index |
         nsc
           add: (ScaledDecimal for: random float scale: 2) ->
             (Date
               newDay: (random integerBetween: 1 and: 365)
               year: (random integerBetween: 2000 and: 2017)) ].
       targetDate1 := Date newDay: 250 year: 2011.
       detectQuery
         bind: 'targetDate'
         to: targetDate1.
       nearestQuery
         bind: 'targetDate'
         to: targetDate1.
       result1 := detectQuery
         detect: [ :date | true ]
         ifNone: [ nearestQuery reversedReadStream next].
       targetDate2 := (nsc _at: 50) value.
       detectQuery
         bind: 'targetDate'
         to: targetDate2.
       nearestQuery
         bind: 'targetDate'
         to: targetDate2.
       result2 := detectQuery
         detect: [ :date | true ]
         ifNone: [ nearestQuery reversedReadStream next].
       {nsc. nsc sortAscending: 'value'. targetDate1. result1. 
targetDate2. result2}


On 8/7/17 6:47 PM, Dale Henrichs wrote:
>
>
> On 8/7/17 1:04 PM, Richard Sargent via Glass wrote:
>> GLASS mailing list wrote
>>> Hi guys,
>>>
>>> I am storing huge lists of "prices". For this, it really helps me to 
>>> store
>>> things ordered (by date)...either in an SequenceableCollection or a
>>> SortedCollection. On the other hand, I do want to use indexes to 
>>> speedup
>>> my
>>> query to find price for a given date (equality index).
>>>
>>> But I have found no way to have them both. The only workaround I 
>>> found is
>>> to keep 2 collections for each of these collections, one 
>>> sorted/ordered,
>>> and the other one an unordered one for querying via index. But this 
>>> is a
>>> pain from "developing" point of view, as well as for unnecessary
>>> repository
>>> growth.
>>>
>>> Am I missing something?
>> Mariano, have you read chapter 7 in the GemStone/S 64 Programming Guide?
>> It's all about indexing.
>>
>> It looks like you could define a "range" query over the unordered 
>> collection
>> to get the sorted sequence needed to traverse all the prices in date 
>> order.
>> The index would be on the date and the range query would be from some 
>> "least
>> date" through some "greatest date". You would then use the streaming 
>> results
>> or the #do: message I think) to iterate over the query result in date 
>> order.
>> There is a section in chapter 7.2 discussing result order.
>>
>>
>> It might be helpful to discuss the use cases for the two collections. 
>> When
>> would you iterate over all the dates versus when would you search for
>> specific dates or ranges of dates?
>>
>>
> Actually I think you can just set up two queries ... one to search for 
> the exact date:
>
>   detectQuery := (GsQuery fromString: 'each.value = targetDate' on: nsc)
>
> and one query to find the first date prior to your targetDate:
>
>   nearestQuery := (GsQuery fromString: 'each.value < targetDate' on: nsc)
>
>
> Then you can use detect:ifNone: sent to the query object itself to 
> either find the first matching date using the index or the first date 
> prior to the target data using an index ... in both queries you are 
> using very efficient btree lookups and avoiding the need to scan your 
> collection (key is the price and value if the date):
>
>       | nsc random maxYear detectQuery targetDate result |
>       nsc := IdentityBag new.
>       random := HostRandom new.
>       GsIndexSpec new
>         equalityIndex: 'value' lastElementClass: Date;
>         createIndexesOn: nsc.
>       1 to: 100 do: [ :index |
>         nsc
>           add: (ScaledDecimal for: random float scale: 2) ->
>             (Date
>               newDay: (random integerBetween: 1 and: 365)
>               year: (random integerBetween: 2000 and: 2017)) ].
>       targetDate := Date newDay: 250 year: 2011.
>       detectQuery := (GsQuery fromString: 'each.value = targetDate' 
> on: nsc)
>         bind: 'targetDate'
>         to: targetDate.
>       result := detectQuery
>         detect: [ :date | true ]
>         ifNone: [ | nearestQuery |
>           nearestQuery :=  (GsQuery fromString: 'each.value < 
> targetDate' on: nsc)
>             bind: 'targetDate'
>             to: targetDate.
>            nearestQuery reversedReadStream next].
>       {nsc. nsc sortAscending: 'value'. targetDate. result}
>
> I'm returning the sorted nsc, to make it easy to validate that the 
> result is correct, since we're generating random dates.
> The parsed query can be persisted (with or without the nsc attached) 
> to avoid the overhead of parsing the query string each time you run 
> the query ...
>



More information about the Glass mailing list